##// END OF EJS Templates
merge with stable
Matt Mackall -
r20702:2764148a merge default
parent child Browse files
Show More
@@ -1,2348 +1,2352 b''
1 # cmdutil.py - help for command processing in mercurial
1 # cmdutil.py - help for command processing in mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, nullid, nullrev, short
8 from node import hex, nullid, nullrev, short
9 from i18n import _
9 from i18n import _
10 import os, sys, errno, re, tempfile
10 import os, sys, errno, re, tempfile
11 import util, scmutil, templater, patch, error, templatekw, revlog, copies
11 import util, scmutil, templater, patch, error, templatekw, revlog, copies
12 import match as matchmod
12 import match as matchmod
13 import context, repair, graphmod, revset, phases, obsolete, pathutil
13 import context, repair, graphmod, revset, phases, obsolete, pathutil
14 import changelog
14 import changelog
15 import bookmarks
15 import bookmarks
16 import lock as lockmod
16 import lock as lockmod
17
17
18 def parsealiases(cmd):
18 def parsealiases(cmd):
19 return cmd.lstrip("^").split("|")
19 return cmd.lstrip("^").split("|")
20
20
21 def findpossible(cmd, table, strict=False):
21 def findpossible(cmd, table, strict=False):
22 """
22 """
23 Return cmd -> (aliases, command table entry)
23 Return cmd -> (aliases, command table entry)
24 for each matching command.
24 for each matching command.
25 Return debug commands (or their aliases) only if no normal command matches.
25 Return debug commands (or their aliases) only if no normal command matches.
26 """
26 """
27 choice = {}
27 choice = {}
28 debugchoice = {}
28 debugchoice = {}
29
29
30 if cmd in table:
30 if cmd in table:
31 # short-circuit exact matches, "log" alias beats "^log|history"
31 # short-circuit exact matches, "log" alias beats "^log|history"
32 keys = [cmd]
32 keys = [cmd]
33 else:
33 else:
34 keys = table.keys()
34 keys = table.keys()
35
35
36 for e in keys:
36 for e in keys:
37 aliases = parsealiases(e)
37 aliases = parsealiases(e)
38 found = None
38 found = None
39 if cmd in aliases:
39 if cmd in aliases:
40 found = cmd
40 found = cmd
41 elif not strict:
41 elif not strict:
42 for a in aliases:
42 for a in aliases:
43 if a.startswith(cmd):
43 if a.startswith(cmd):
44 found = a
44 found = a
45 break
45 break
46 if found is not None:
46 if found is not None:
47 if aliases[0].startswith("debug") or found.startswith("debug"):
47 if aliases[0].startswith("debug") or found.startswith("debug"):
48 debugchoice[found] = (aliases, table[e])
48 debugchoice[found] = (aliases, table[e])
49 else:
49 else:
50 choice[found] = (aliases, table[e])
50 choice[found] = (aliases, table[e])
51
51
52 if not choice and debugchoice:
52 if not choice and debugchoice:
53 choice = debugchoice
53 choice = debugchoice
54
54
55 return choice
55 return choice
56
56
57 def findcmd(cmd, table, strict=True):
57 def findcmd(cmd, table, strict=True):
58 """Return (aliases, command table entry) for command string."""
58 """Return (aliases, command table entry) for command string."""
59 choice = findpossible(cmd, table, strict)
59 choice = findpossible(cmd, table, strict)
60
60
61 if cmd in choice:
61 if cmd in choice:
62 return choice[cmd]
62 return choice[cmd]
63
63
64 if len(choice) > 1:
64 if len(choice) > 1:
65 clist = choice.keys()
65 clist = choice.keys()
66 clist.sort()
66 clist.sort()
67 raise error.AmbiguousCommand(cmd, clist)
67 raise error.AmbiguousCommand(cmd, clist)
68
68
69 if choice:
69 if choice:
70 return choice.values()[0]
70 return choice.values()[0]
71
71
72 raise error.UnknownCommand(cmd)
72 raise error.UnknownCommand(cmd)
73
73
74 def findrepo(p):
74 def findrepo(p):
75 while not os.path.isdir(os.path.join(p, ".hg")):
75 while not os.path.isdir(os.path.join(p, ".hg")):
76 oldp, p = p, os.path.dirname(p)
76 oldp, p = p, os.path.dirname(p)
77 if p == oldp:
77 if p == oldp:
78 return None
78 return None
79
79
80 return p
80 return p
81
81
82 def bailifchanged(repo):
82 def bailifchanged(repo):
83 if repo.dirstate.p2() != nullid:
83 if repo.dirstate.p2() != nullid:
84 raise util.Abort(_('outstanding uncommitted merge'))
84 raise util.Abort(_('outstanding uncommitted merge'))
85 modified, added, removed, deleted = repo.status()[:4]
85 modified, added, removed, deleted = repo.status()[:4]
86 if modified or added or removed or deleted:
86 if modified or added or removed or deleted:
87 raise util.Abort(_('uncommitted changes'))
87 raise util.Abort(_('uncommitted changes'))
88 ctx = repo[None]
88 ctx = repo[None]
89 for s in sorted(ctx.substate):
89 for s in sorted(ctx.substate):
90 if ctx.sub(s).dirty():
90 if ctx.sub(s).dirty():
91 raise util.Abort(_("uncommitted changes in subrepo %s") % s)
91 raise util.Abort(_("uncommitted changes in subrepo %s") % s)
92
92
93 def logmessage(ui, opts):
93 def logmessage(ui, opts):
94 """ get the log message according to -m and -l option """
94 """ get the log message according to -m and -l option """
95 message = opts.get('message')
95 message = opts.get('message')
96 logfile = opts.get('logfile')
96 logfile = opts.get('logfile')
97
97
98 if message and logfile:
98 if message and logfile:
99 raise util.Abort(_('options --message and --logfile are mutually '
99 raise util.Abort(_('options --message and --logfile are mutually '
100 'exclusive'))
100 'exclusive'))
101 if not message and logfile:
101 if not message and logfile:
102 try:
102 try:
103 if logfile == '-':
103 if logfile == '-':
104 message = ui.fin.read()
104 message = ui.fin.read()
105 else:
105 else:
106 message = '\n'.join(util.readfile(logfile).splitlines())
106 message = '\n'.join(util.readfile(logfile).splitlines())
107 except IOError, inst:
107 except IOError, inst:
108 raise util.Abort(_("can't read commit message '%s': %s") %
108 raise util.Abort(_("can't read commit message '%s': %s") %
109 (logfile, inst.strerror))
109 (logfile, inst.strerror))
110 return message
110 return message
111
111
112 def loglimit(opts):
112 def loglimit(opts):
113 """get the log limit according to option -l/--limit"""
113 """get the log limit according to option -l/--limit"""
114 limit = opts.get('limit')
114 limit = opts.get('limit')
115 if limit:
115 if limit:
116 try:
116 try:
117 limit = int(limit)
117 limit = int(limit)
118 except ValueError:
118 except ValueError:
119 raise util.Abort(_('limit must be a positive integer'))
119 raise util.Abort(_('limit must be a positive integer'))
120 if limit <= 0:
120 if limit <= 0:
121 raise util.Abort(_('limit must be positive'))
121 raise util.Abort(_('limit must be positive'))
122 else:
122 else:
123 limit = None
123 limit = None
124 return limit
124 return limit
125
125
126 def makefilename(repo, pat, node, desc=None,
126 def makefilename(repo, pat, node, desc=None,
127 total=None, seqno=None, revwidth=None, pathname=None):
127 total=None, seqno=None, revwidth=None, pathname=None):
128 node_expander = {
128 node_expander = {
129 'H': lambda: hex(node),
129 'H': lambda: hex(node),
130 'R': lambda: str(repo.changelog.rev(node)),
130 'R': lambda: str(repo.changelog.rev(node)),
131 'h': lambda: short(node),
131 'h': lambda: short(node),
132 'm': lambda: re.sub('[^\w]', '_', str(desc))
132 'm': lambda: re.sub('[^\w]', '_', str(desc))
133 }
133 }
134 expander = {
134 expander = {
135 '%': lambda: '%',
135 '%': lambda: '%',
136 'b': lambda: os.path.basename(repo.root),
136 'b': lambda: os.path.basename(repo.root),
137 }
137 }
138
138
139 try:
139 try:
140 if node:
140 if node:
141 expander.update(node_expander)
141 expander.update(node_expander)
142 if node:
142 if node:
143 expander['r'] = (lambda:
143 expander['r'] = (lambda:
144 str(repo.changelog.rev(node)).zfill(revwidth or 0))
144 str(repo.changelog.rev(node)).zfill(revwidth or 0))
145 if total is not None:
145 if total is not None:
146 expander['N'] = lambda: str(total)
146 expander['N'] = lambda: str(total)
147 if seqno is not None:
147 if seqno is not None:
148 expander['n'] = lambda: str(seqno)
148 expander['n'] = lambda: str(seqno)
149 if total is not None and seqno is not None:
149 if total is not None and seqno is not None:
150 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
150 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
151 if pathname is not None:
151 if pathname is not None:
152 expander['s'] = lambda: os.path.basename(pathname)
152 expander['s'] = lambda: os.path.basename(pathname)
153 expander['d'] = lambda: os.path.dirname(pathname) or '.'
153 expander['d'] = lambda: os.path.dirname(pathname) or '.'
154 expander['p'] = lambda: pathname
154 expander['p'] = lambda: pathname
155
155
156 newname = []
156 newname = []
157 patlen = len(pat)
157 patlen = len(pat)
158 i = 0
158 i = 0
159 while i < patlen:
159 while i < patlen:
160 c = pat[i]
160 c = pat[i]
161 if c == '%':
161 if c == '%':
162 i += 1
162 i += 1
163 c = pat[i]
163 c = pat[i]
164 c = expander[c]()
164 c = expander[c]()
165 newname.append(c)
165 newname.append(c)
166 i += 1
166 i += 1
167 return ''.join(newname)
167 return ''.join(newname)
168 except KeyError, inst:
168 except KeyError, inst:
169 raise util.Abort(_("invalid format spec '%%%s' in output filename") %
169 raise util.Abort(_("invalid format spec '%%%s' in output filename") %
170 inst.args[0])
170 inst.args[0])
171
171
172 def makefileobj(repo, pat, node=None, desc=None, total=None,
172 def makefileobj(repo, pat, node=None, desc=None, total=None,
173 seqno=None, revwidth=None, mode='wb', modemap=None,
173 seqno=None, revwidth=None, mode='wb', modemap=None,
174 pathname=None):
174 pathname=None):
175
175
176 writable = mode not in ('r', 'rb')
176 writable = mode not in ('r', 'rb')
177
177
178 if not pat or pat == '-':
178 if not pat or pat == '-':
179 fp = writable and repo.ui.fout or repo.ui.fin
179 fp = writable and repo.ui.fout or repo.ui.fin
180 if util.safehasattr(fp, 'fileno'):
180 if util.safehasattr(fp, 'fileno'):
181 return os.fdopen(os.dup(fp.fileno()), mode)
181 return os.fdopen(os.dup(fp.fileno()), mode)
182 else:
182 else:
183 # if this fp can't be duped properly, return
183 # if this fp can't be duped properly, return
184 # a dummy object that can be closed
184 # a dummy object that can be closed
185 class wrappedfileobj(object):
185 class wrappedfileobj(object):
186 noop = lambda x: None
186 noop = lambda x: None
187 def __init__(self, f):
187 def __init__(self, f):
188 self.f = f
188 self.f = f
189 def __getattr__(self, attr):
189 def __getattr__(self, attr):
190 if attr == 'close':
190 if attr == 'close':
191 return self.noop
191 return self.noop
192 else:
192 else:
193 return getattr(self.f, attr)
193 return getattr(self.f, attr)
194
194
195 return wrappedfileobj(fp)
195 return wrappedfileobj(fp)
196 if util.safehasattr(pat, 'write') and writable:
196 if util.safehasattr(pat, 'write') and writable:
197 return pat
197 return pat
198 if util.safehasattr(pat, 'read') and 'r' in mode:
198 if util.safehasattr(pat, 'read') and 'r' in mode:
199 return pat
199 return pat
200 fn = makefilename(repo, pat, node, desc, total, seqno, revwidth, pathname)
200 fn = makefilename(repo, pat, node, desc, total, seqno, revwidth, pathname)
201 if modemap is not None:
201 if modemap is not None:
202 mode = modemap.get(fn, mode)
202 mode = modemap.get(fn, mode)
203 if mode == 'wb':
203 if mode == 'wb':
204 modemap[fn] = 'ab'
204 modemap[fn] = 'ab'
205 return open(fn, mode)
205 return open(fn, mode)
206
206
207 def openrevlog(repo, cmd, file_, opts):
207 def openrevlog(repo, cmd, file_, opts):
208 """opens the changelog, manifest, a filelog or a given revlog"""
208 """opens the changelog, manifest, a filelog or a given revlog"""
209 cl = opts['changelog']
209 cl = opts['changelog']
210 mf = opts['manifest']
210 mf = opts['manifest']
211 msg = None
211 msg = None
212 if cl and mf:
212 if cl and mf:
213 msg = _('cannot specify --changelog and --manifest at the same time')
213 msg = _('cannot specify --changelog and --manifest at the same time')
214 elif cl or mf:
214 elif cl or mf:
215 if file_:
215 if file_:
216 msg = _('cannot specify filename with --changelog or --manifest')
216 msg = _('cannot specify filename with --changelog or --manifest')
217 elif not repo:
217 elif not repo:
218 msg = _('cannot specify --changelog or --manifest '
218 msg = _('cannot specify --changelog or --manifest '
219 'without a repository')
219 'without a repository')
220 if msg:
220 if msg:
221 raise util.Abort(msg)
221 raise util.Abort(msg)
222
222
223 r = None
223 r = None
224 if repo:
224 if repo:
225 if cl:
225 if cl:
226 r = repo.changelog
226 r = repo.changelog
227 elif mf:
227 elif mf:
228 r = repo.manifest
228 r = repo.manifest
229 elif file_:
229 elif file_:
230 filelog = repo.file(file_)
230 filelog = repo.file(file_)
231 if len(filelog):
231 if len(filelog):
232 r = filelog
232 r = filelog
233 if not r:
233 if not r:
234 if not file_:
234 if not file_:
235 raise error.CommandError(cmd, _('invalid arguments'))
235 raise error.CommandError(cmd, _('invalid arguments'))
236 if not os.path.isfile(file_):
236 if not os.path.isfile(file_):
237 raise util.Abort(_("revlog '%s' not found") % file_)
237 raise util.Abort(_("revlog '%s' not found") % file_)
238 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
238 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
239 file_[:-2] + ".i")
239 file_[:-2] + ".i")
240 return r
240 return r
241
241
242 def copy(ui, repo, pats, opts, rename=False):
242 def copy(ui, repo, pats, opts, rename=False):
243 # called with the repo lock held
243 # called with the repo lock held
244 #
244 #
245 # hgsep => pathname that uses "/" to separate directories
245 # hgsep => pathname that uses "/" to separate directories
246 # ossep => pathname that uses os.sep to separate directories
246 # ossep => pathname that uses os.sep to separate directories
247 cwd = repo.getcwd()
247 cwd = repo.getcwd()
248 targets = {}
248 targets = {}
249 after = opts.get("after")
249 after = opts.get("after")
250 dryrun = opts.get("dry_run")
250 dryrun = opts.get("dry_run")
251 wctx = repo[None]
251 wctx = repo[None]
252
252
253 def walkpat(pat):
253 def walkpat(pat):
254 srcs = []
254 srcs = []
255 badstates = after and '?' or '?r'
255 badstates = after and '?' or '?r'
256 m = scmutil.match(repo[None], [pat], opts, globbed=True)
256 m = scmutil.match(repo[None], [pat], opts, globbed=True)
257 for abs in repo.walk(m):
257 for abs in repo.walk(m):
258 state = repo.dirstate[abs]
258 state = repo.dirstate[abs]
259 rel = m.rel(abs)
259 rel = m.rel(abs)
260 exact = m.exact(abs)
260 exact = m.exact(abs)
261 if state in badstates:
261 if state in badstates:
262 if exact and state == '?':
262 if exact and state == '?':
263 ui.warn(_('%s: not copying - file is not managed\n') % rel)
263 ui.warn(_('%s: not copying - file is not managed\n') % rel)
264 if exact and state == 'r':
264 if exact and state == 'r':
265 ui.warn(_('%s: not copying - file has been marked for'
265 ui.warn(_('%s: not copying - file has been marked for'
266 ' remove\n') % rel)
266 ' remove\n') % rel)
267 continue
267 continue
268 # abs: hgsep
268 # abs: hgsep
269 # rel: ossep
269 # rel: ossep
270 srcs.append((abs, rel, exact))
270 srcs.append((abs, rel, exact))
271 return srcs
271 return srcs
272
272
273 # abssrc: hgsep
273 # abssrc: hgsep
274 # relsrc: ossep
274 # relsrc: ossep
275 # otarget: ossep
275 # otarget: ossep
276 def copyfile(abssrc, relsrc, otarget, exact):
276 def copyfile(abssrc, relsrc, otarget, exact):
277 abstarget = pathutil.canonpath(repo.root, cwd, otarget)
277 abstarget = pathutil.canonpath(repo.root, cwd, otarget)
278 if '/' in abstarget:
278 if '/' in abstarget:
279 # We cannot normalize abstarget itself, this would prevent
279 # We cannot normalize abstarget itself, this would prevent
280 # case only renames, like a => A.
280 # case only renames, like a => A.
281 abspath, absname = abstarget.rsplit('/', 1)
281 abspath, absname = abstarget.rsplit('/', 1)
282 abstarget = repo.dirstate.normalize(abspath) + '/' + absname
282 abstarget = repo.dirstate.normalize(abspath) + '/' + absname
283 reltarget = repo.pathto(abstarget, cwd)
283 reltarget = repo.pathto(abstarget, cwd)
284 target = repo.wjoin(abstarget)
284 target = repo.wjoin(abstarget)
285 src = repo.wjoin(abssrc)
285 src = repo.wjoin(abssrc)
286 state = repo.dirstate[abstarget]
286 state = repo.dirstate[abstarget]
287
287
288 scmutil.checkportable(ui, abstarget)
288 scmutil.checkportable(ui, abstarget)
289
289
290 # check for collisions
290 # check for collisions
291 prevsrc = targets.get(abstarget)
291 prevsrc = targets.get(abstarget)
292 if prevsrc is not None:
292 if prevsrc is not None:
293 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
293 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
294 (reltarget, repo.pathto(abssrc, cwd),
294 (reltarget, repo.pathto(abssrc, cwd),
295 repo.pathto(prevsrc, cwd)))
295 repo.pathto(prevsrc, cwd)))
296 return
296 return
297
297
298 # check for overwrites
298 # check for overwrites
299 exists = os.path.lexists(target)
299 exists = os.path.lexists(target)
300 samefile = False
300 samefile = False
301 if exists and abssrc != abstarget:
301 if exists and abssrc != abstarget:
302 if (repo.dirstate.normalize(abssrc) ==
302 if (repo.dirstate.normalize(abssrc) ==
303 repo.dirstate.normalize(abstarget)):
303 repo.dirstate.normalize(abstarget)):
304 if not rename:
304 if not rename:
305 ui.warn(_("%s: can't copy - same file\n") % reltarget)
305 ui.warn(_("%s: can't copy - same file\n") % reltarget)
306 return
306 return
307 exists = False
307 exists = False
308 samefile = True
308 samefile = True
309
309
310 if not after and exists or after and state in 'mn':
310 if not after and exists or after and state in 'mn':
311 if not opts['force']:
311 if not opts['force']:
312 ui.warn(_('%s: not overwriting - file exists\n') %
312 ui.warn(_('%s: not overwriting - file exists\n') %
313 reltarget)
313 reltarget)
314 return
314 return
315
315
316 if after:
316 if after:
317 if not exists:
317 if not exists:
318 if rename:
318 if rename:
319 ui.warn(_('%s: not recording move - %s does not exist\n') %
319 ui.warn(_('%s: not recording move - %s does not exist\n') %
320 (relsrc, reltarget))
320 (relsrc, reltarget))
321 else:
321 else:
322 ui.warn(_('%s: not recording copy - %s does not exist\n') %
322 ui.warn(_('%s: not recording copy - %s does not exist\n') %
323 (relsrc, reltarget))
323 (relsrc, reltarget))
324 return
324 return
325 elif not dryrun:
325 elif not dryrun:
326 try:
326 try:
327 if exists:
327 if exists:
328 os.unlink(target)
328 os.unlink(target)
329 targetdir = os.path.dirname(target) or '.'
329 targetdir = os.path.dirname(target) or '.'
330 if not os.path.isdir(targetdir):
330 if not os.path.isdir(targetdir):
331 os.makedirs(targetdir)
331 os.makedirs(targetdir)
332 if samefile:
332 if samefile:
333 tmp = target + "~hgrename"
333 tmp = target + "~hgrename"
334 os.rename(src, tmp)
334 os.rename(src, tmp)
335 os.rename(tmp, target)
335 os.rename(tmp, target)
336 else:
336 else:
337 util.copyfile(src, target)
337 util.copyfile(src, target)
338 srcexists = True
338 srcexists = True
339 except IOError, inst:
339 except IOError, inst:
340 if inst.errno == errno.ENOENT:
340 if inst.errno == errno.ENOENT:
341 ui.warn(_('%s: deleted in working copy\n') % relsrc)
341 ui.warn(_('%s: deleted in working copy\n') % relsrc)
342 srcexists = False
342 srcexists = False
343 else:
343 else:
344 ui.warn(_('%s: cannot copy - %s\n') %
344 ui.warn(_('%s: cannot copy - %s\n') %
345 (relsrc, inst.strerror))
345 (relsrc, inst.strerror))
346 return True # report a failure
346 return True # report a failure
347
347
348 if ui.verbose or not exact:
348 if ui.verbose or not exact:
349 if rename:
349 if rename:
350 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
350 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
351 else:
351 else:
352 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
352 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
353
353
354 targets[abstarget] = abssrc
354 targets[abstarget] = abssrc
355
355
356 # fix up dirstate
356 # fix up dirstate
357 scmutil.dirstatecopy(ui, repo, wctx, abssrc, abstarget,
357 scmutil.dirstatecopy(ui, repo, wctx, abssrc, abstarget,
358 dryrun=dryrun, cwd=cwd)
358 dryrun=dryrun, cwd=cwd)
359 if rename and not dryrun:
359 if rename and not dryrun:
360 if not after and srcexists and not samefile:
360 if not after and srcexists and not samefile:
361 util.unlinkpath(repo.wjoin(abssrc))
361 util.unlinkpath(repo.wjoin(abssrc))
362 wctx.forget([abssrc])
362 wctx.forget([abssrc])
363
363
364 # pat: ossep
364 # pat: ossep
365 # dest ossep
365 # dest ossep
366 # srcs: list of (hgsep, hgsep, ossep, bool)
366 # srcs: list of (hgsep, hgsep, ossep, bool)
367 # return: function that takes hgsep and returns ossep
367 # return: function that takes hgsep and returns ossep
368 def targetpathfn(pat, dest, srcs):
368 def targetpathfn(pat, dest, srcs):
369 if os.path.isdir(pat):
369 if os.path.isdir(pat):
370 abspfx = pathutil.canonpath(repo.root, cwd, pat)
370 abspfx = pathutil.canonpath(repo.root, cwd, pat)
371 abspfx = util.localpath(abspfx)
371 abspfx = util.localpath(abspfx)
372 if destdirexists:
372 if destdirexists:
373 striplen = len(os.path.split(abspfx)[0])
373 striplen = len(os.path.split(abspfx)[0])
374 else:
374 else:
375 striplen = len(abspfx)
375 striplen = len(abspfx)
376 if striplen:
376 if striplen:
377 striplen += len(os.sep)
377 striplen += len(os.sep)
378 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
378 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
379 elif destdirexists:
379 elif destdirexists:
380 res = lambda p: os.path.join(dest,
380 res = lambda p: os.path.join(dest,
381 os.path.basename(util.localpath(p)))
381 os.path.basename(util.localpath(p)))
382 else:
382 else:
383 res = lambda p: dest
383 res = lambda p: dest
384 return res
384 return res
385
385
386 # pat: ossep
386 # pat: ossep
387 # dest ossep
387 # dest ossep
388 # srcs: list of (hgsep, hgsep, ossep, bool)
388 # srcs: list of (hgsep, hgsep, ossep, bool)
389 # return: function that takes hgsep and returns ossep
389 # return: function that takes hgsep and returns ossep
390 def targetpathafterfn(pat, dest, srcs):
390 def targetpathafterfn(pat, dest, srcs):
391 if matchmod.patkind(pat):
391 if matchmod.patkind(pat):
392 # a mercurial pattern
392 # a mercurial pattern
393 res = lambda p: os.path.join(dest,
393 res = lambda p: os.path.join(dest,
394 os.path.basename(util.localpath(p)))
394 os.path.basename(util.localpath(p)))
395 else:
395 else:
396 abspfx = pathutil.canonpath(repo.root, cwd, pat)
396 abspfx = pathutil.canonpath(repo.root, cwd, pat)
397 if len(abspfx) < len(srcs[0][0]):
397 if len(abspfx) < len(srcs[0][0]):
398 # A directory. Either the target path contains the last
398 # A directory. Either the target path contains the last
399 # component of the source path or it does not.
399 # component of the source path or it does not.
400 def evalpath(striplen):
400 def evalpath(striplen):
401 score = 0
401 score = 0
402 for s in srcs:
402 for s in srcs:
403 t = os.path.join(dest, util.localpath(s[0])[striplen:])
403 t = os.path.join(dest, util.localpath(s[0])[striplen:])
404 if os.path.lexists(t):
404 if os.path.lexists(t):
405 score += 1
405 score += 1
406 return score
406 return score
407
407
408 abspfx = util.localpath(abspfx)
408 abspfx = util.localpath(abspfx)
409 striplen = len(abspfx)
409 striplen = len(abspfx)
410 if striplen:
410 if striplen:
411 striplen += len(os.sep)
411 striplen += len(os.sep)
412 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
412 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
413 score = evalpath(striplen)
413 score = evalpath(striplen)
414 striplen1 = len(os.path.split(abspfx)[0])
414 striplen1 = len(os.path.split(abspfx)[0])
415 if striplen1:
415 if striplen1:
416 striplen1 += len(os.sep)
416 striplen1 += len(os.sep)
417 if evalpath(striplen1) > score:
417 if evalpath(striplen1) > score:
418 striplen = striplen1
418 striplen = striplen1
419 res = lambda p: os.path.join(dest,
419 res = lambda p: os.path.join(dest,
420 util.localpath(p)[striplen:])
420 util.localpath(p)[striplen:])
421 else:
421 else:
422 # a file
422 # a file
423 if destdirexists:
423 if destdirexists:
424 res = lambda p: os.path.join(dest,
424 res = lambda p: os.path.join(dest,
425 os.path.basename(util.localpath(p)))
425 os.path.basename(util.localpath(p)))
426 else:
426 else:
427 res = lambda p: dest
427 res = lambda p: dest
428 return res
428 return res
429
429
430
430
431 pats = scmutil.expandpats(pats)
431 pats = scmutil.expandpats(pats)
432 if not pats:
432 if not pats:
433 raise util.Abort(_('no source or destination specified'))
433 raise util.Abort(_('no source or destination specified'))
434 if len(pats) == 1:
434 if len(pats) == 1:
435 raise util.Abort(_('no destination specified'))
435 raise util.Abort(_('no destination specified'))
436 dest = pats.pop()
436 dest = pats.pop()
437 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
437 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
438 if not destdirexists:
438 if not destdirexists:
439 if len(pats) > 1 or matchmod.patkind(pats[0]):
439 if len(pats) > 1 or matchmod.patkind(pats[0]):
440 raise util.Abort(_('with multiple sources, destination must be an '
440 raise util.Abort(_('with multiple sources, destination must be an '
441 'existing directory'))
441 'existing directory'))
442 if util.endswithsep(dest):
442 if util.endswithsep(dest):
443 raise util.Abort(_('destination %s is not a directory') % dest)
443 raise util.Abort(_('destination %s is not a directory') % dest)
444
444
445 tfn = targetpathfn
445 tfn = targetpathfn
446 if after:
446 if after:
447 tfn = targetpathafterfn
447 tfn = targetpathafterfn
448 copylist = []
448 copylist = []
449 for pat in pats:
449 for pat in pats:
450 srcs = walkpat(pat)
450 srcs = walkpat(pat)
451 if not srcs:
451 if not srcs:
452 continue
452 continue
453 copylist.append((tfn(pat, dest, srcs), srcs))
453 copylist.append((tfn(pat, dest, srcs), srcs))
454 if not copylist:
454 if not copylist:
455 raise util.Abort(_('no files to copy'))
455 raise util.Abort(_('no files to copy'))
456
456
457 errors = 0
457 errors = 0
458 for targetpath, srcs in copylist:
458 for targetpath, srcs in copylist:
459 for abssrc, relsrc, exact in srcs:
459 for abssrc, relsrc, exact in srcs:
460 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
460 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
461 errors += 1
461 errors += 1
462
462
463 if errors:
463 if errors:
464 ui.warn(_('(consider using --after)\n'))
464 ui.warn(_('(consider using --after)\n'))
465
465
466 return errors != 0
466 return errors != 0
467
467
468 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
468 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
469 runargs=None, appendpid=False):
469 runargs=None, appendpid=False):
470 '''Run a command as a service.'''
470 '''Run a command as a service.'''
471
471
472 def writepid(pid):
472 def writepid(pid):
473 if opts['pid_file']:
473 if opts['pid_file']:
474 mode = appendpid and 'a' or 'w'
474 mode = appendpid and 'a' or 'w'
475 fp = open(opts['pid_file'], mode)
475 fp = open(opts['pid_file'], mode)
476 fp.write(str(pid) + '\n')
476 fp.write(str(pid) + '\n')
477 fp.close()
477 fp.close()
478
478
479 if opts['daemon'] and not opts['daemon_pipefds']:
479 if opts['daemon'] and not opts['daemon_pipefds']:
480 # Signal child process startup with file removal
480 # Signal child process startup with file removal
481 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
481 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
482 os.close(lockfd)
482 os.close(lockfd)
483 try:
483 try:
484 if not runargs:
484 if not runargs:
485 runargs = util.hgcmd() + sys.argv[1:]
485 runargs = util.hgcmd() + sys.argv[1:]
486 runargs.append('--daemon-pipefds=%s' % lockpath)
486 runargs.append('--daemon-pipefds=%s' % lockpath)
487 # Don't pass --cwd to the child process, because we've already
487 # Don't pass --cwd to the child process, because we've already
488 # changed directory.
488 # changed directory.
489 for i in xrange(1, len(runargs)):
489 for i in xrange(1, len(runargs)):
490 if runargs[i].startswith('--cwd='):
490 if runargs[i].startswith('--cwd='):
491 del runargs[i]
491 del runargs[i]
492 break
492 break
493 elif runargs[i].startswith('--cwd'):
493 elif runargs[i].startswith('--cwd'):
494 del runargs[i:i + 2]
494 del runargs[i:i + 2]
495 break
495 break
496 def condfn():
496 def condfn():
497 return not os.path.exists(lockpath)
497 return not os.path.exists(lockpath)
498 pid = util.rundetached(runargs, condfn)
498 pid = util.rundetached(runargs, condfn)
499 if pid < 0:
499 if pid < 0:
500 raise util.Abort(_('child process failed to start'))
500 raise util.Abort(_('child process failed to start'))
501 writepid(pid)
501 writepid(pid)
502 finally:
502 finally:
503 try:
503 try:
504 os.unlink(lockpath)
504 os.unlink(lockpath)
505 except OSError, e:
505 except OSError, e:
506 if e.errno != errno.ENOENT:
506 if e.errno != errno.ENOENT:
507 raise
507 raise
508 if parentfn:
508 if parentfn:
509 return parentfn(pid)
509 return parentfn(pid)
510 else:
510 else:
511 return
511 return
512
512
513 if initfn:
513 if initfn:
514 initfn()
514 initfn()
515
515
516 if not opts['daemon']:
516 if not opts['daemon']:
517 writepid(os.getpid())
517 writepid(os.getpid())
518
518
519 if opts['daemon_pipefds']:
519 if opts['daemon_pipefds']:
520 lockpath = opts['daemon_pipefds']
520 lockpath = opts['daemon_pipefds']
521 try:
521 try:
522 os.setsid()
522 os.setsid()
523 except AttributeError:
523 except AttributeError:
524 pass
524 pass
525 os.unlink(lockpath)
525 os.unlink(lockpath)
526 util.hidewindow()
526 util.hidewindow()
527 sys.stdout.flush()
527 sys.stdout.flush()
528 sys.stderr.flush()
528 sys.stderr.flush()
529
529
530 nullfd = os.open(os.devnull, os.O_RDWR)
530 nullfd = os.open(os.devnull, os.O_RDWR)
531 logfilefd = nullfd
531 logfilefd = nullfd
532 if logfile:
532 if logfile:
533 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
533 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
534 os.dup2(nullfd, 0)
534 os.dup2(nullfd, 0)
535 os.dup2(logfilefd, 1)
535 os.dup2(logfilefd, 1)
536 os.dup2(logfilefd, 2)
536 os.dup2(logfilefd, 2)
537 if nullfd not in (0, 1, 2):
537 if nullfd not in (0, 1, 2):
538 os.close(nullfd)
538 os.close(nullfd)
539 if logfile and logfilefd not in (0, 1, 2):
539 if logfile and logfilefd not in (0, 1, 2):
540 os.close(logfilefd)
540 os.close(logfilefd)
541
541
542 if runfn:
542 if runfn:
543 return runfn()
543 return runfn()
544
544
545 def tryimportone(ui, repo, hunk, parents, opts, msgs, updatefunc):
545 def tryimportone(ui, repo, hunk, parents, opts, msgs, updatefunc):
546 """Utility function used by commands.import to import a single patch
546 """Utility function used by commands.import to import a single patch
547
547
548 This function is explicitly defined here to help the evolve extension to
548 This function is explicitly defined here to help the evolve extension to
549 wrap this part of the import logic.
549 wrap this part of the import logic.
550
550
551 The API is currently a bit ugly because it a simple code translation from
551 The API is currently a bit ugly because it a simple code translation from
552 the import command. Feel free to make it better.
552 the import command. Feel free to make it better.
553
553
554 :hunk: a patch (as a binary string)
554 :hunk: a patch (as a binary string)
555 :parents: nodes that will be parent of the created commit
555 :parents: nodes that will be parent of the created commit
556 :opts: the full dict of option passed to the import command
556 :opts: the full dict of option passed to the import command
557 :msgs: list to save commit message to.
557 :msgs: list to save commit message to.
558 (used in case we need to save it when failing)
558 (used in case we need to save it when failing)
559 :updatefunc: a function that update a repo to a given node
559 :updatefunc: a function that update a repo to a given node
560 updatefunc(<repo>, <node>)
560 updatefunc(<repo>, <node>)
561 """
561 """
562 tmpname, message, user, date, branch, nodeid, p1, p2 = \
562 tmpname, message, user, date, branch, nodeid, p1, p2 = \
563 patch.extract(ui, hunk)
563 patch.extract(ui, hunk)
564
564
565 editor = commiteditor
565 editor = commiteditor
566 if opts.get('edit'):
566 if opts.get('edit'):
567 editor = commitforceeditor
567 editor = commitforceeditor
568 update = not opts.get('bypass')
568 update = not opts.get('bypass')
569 strip = opts["strip"]
569 strip = opts["strip"]
570 sim = float(opts.get('similarity') or 0)
570 sim = float(opts.get('similarity') or 0)
571 if not tmpname:
571 if not tmpname:
572 return (None, None)
572 return (None, None)
573 msg = _('applied to working directory')
573 msg = _('applied to working directory')
574
574
575 try:
575 try:
576 cmdline_message = logmessage(ui, opts)
576 cmdline_message = logmessage(ui, opts)
577 if cmdline_message:
577 if cmdline_message:
578 # pickup the cmdline msg
578 # pickup the cmdline msg
579 message = cmdline_message
579 message = cmdline_message
580 elif message:
580 elif message:
581 # pickup the patch msg
581 # pickup the patch msg
582 message = message.strip()
582 message = message.strip()
583 else:
583 else:
584 # launch the editor
584 # launch the editor
585 message = None
585 message = None
586 ui.debug('message:\n%s\n' % message)
586 ui.debug('message:\n%s\n' % message)
587
587
588 if len(parents) == 1:
588 if len(parents) == 1:
589 parents.append(repo[nullid])
589 parents.append(repo[nullid])
590 if opts.get('exact'):
590 if opts.get('exact'):
591 if not nodeid or not p1:
591 if not nodeid or not p1:
592 raise util.Abort(_('not a Mercurial patch'))
592 raise util.Abort(_('not a Mercurial patch'))
593 p1 = repo[p1]
593 p1 = repo[p1]
594 p2 = repo[p2 or nullid]
594 p2 = repo[p2 or nullid]
595 elif p2:
595 elif p2:
596 try:
596 try:
597 p1 = repo[p1]
597 p1 = repo[p1]
598 p2 = repo[p2]
598 p2 = repo[p2]
599 # Without any options, consider p2 only if the
599 # Without any options, consider p2 only if the
600 # patch is being applied on top of the recorded
600 # patch is being applied on top of the recorded
601 # first parent.
601 # first parent.
602 if p1 != parents[0]:
602 if p1 != parents[0]:
603 p1 = parents[0]
603 p1 = parents[0]
604 p2 = repo[nullid]
604 p2 = repo[nullid]
605 except error.RepoError:
605 except error.RepoError:
606 p1, p2 = parents
606 p1, p2 = parents
607 else:
607 else:
608 p1, p2 = parents
608 p1, p2 = parents
609
609
610 n = None
610 n = None
611 if update:
611 if update:
612 if p1 != parents[0]:
612 if p1 != parents[0]:
613 updatefunc(repo, p1.node())
613 updatefunc(repo, p1.node())
614 if p2 != parents[1]:
614 if p2 != parents[1]:
615 repo.setparents(p1.node(), p2.node())
615 repo.setparents(p1.node(), p2.node())
616
616
617 if opts.get('exact') or opts.get('import_branch'):
617 if opts.get('exact') or opts.get('import_branch'):
618 repo.dirstate.setbranch(branch or 'default')
618 repo.dirstate.setbranch(branch or 'default')
619
619
620 files = set()
620 files = set()
621 patch.patch(ui, repo, tmpname, strip=strip, files=files,
621 patch.patch(ui, repo, tmpname, strip=strip, files=files,
622 eolmode=None, similarity=sim / 100.0)
622 eolmode=None, similarity=sim / 100.0)
623 files = list(files)
623 files = list(files)
624 if opts.get('no_commit'):
624 if opts.get('no_commit'):
625 if message:
625 if message:
626 msgs.append(message)
626 msgs.append(message)
627 else:
627 else:
628 if opts.get('exact') or p2:
628 if opts.get('exact') or p2:
629 # If you got here, you either use --force and know what
629 # If you got here, you either use --force and know what
630 # you are doing or used --exact or a merge patch while
630 # you are doing or used --exact or a merge patch while
631 # being updated to its first parent.
631 # being updated to its first parent.
632 m = None
632 m = None
633 else:
633 else:
634 m = scmutil.matchfiles(repo, files or [])
634 m = scmutil.matchfiles(repo, files or [])
635 n = repo.commit(message, opts.get('user') or user,
635 n = repo.commit(message, opts.get('user') or user,
636 opts.get('date') or date, match=m,
636 opts.get('date') or date, match=m,
637 editor=editor)
637 editor=editor)
638 else:
638 else:
639 if opts.get('exact') or opts.get('import_branch'):
639 if opts.get('exact') or opts.get('import_branch'):
640 branch = branch or 'default'
640 branch = branch or 'default'
641 else:
641 else:
642 branch = p1.branch()
642 branch = p1.branch()
643 store = patch.filestore()
643 store = patch.filestore()
644 try:
644 try:
645 files = set()
645 files = set()
646 try:
646 try:
647 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
647 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
648 files, eolmode=None)
648 files, eolmode=None)
649 except patch.PatchError, e:
649 except patch.PatchError, e:
650 raise util.Abort(str(e))
650 raise util.Abort(str(e))
651 memctx = context.makememctx(repo, (p1.node(), p2.node()),
651 memctx = context.makememctx(repo, (p1.node(), p2.node()),
652 message,
652 message,
653 opts.get('user') or user,
653 opts.get('user') or user,
654 opts.get('date') or date,
654 opts.get('date') or date,
655 branch, files, store,
655 branch, files, store,
656 editor=commiteditor)
656 editor=commiteditor)
657 repo.savecommitmessage(memctx.description())
657 repo.savecommitmessage(memctx.description())
658 n = memctx.commit()
658 n = memctx.commit()
659 finally:
659 finally:
660 store.close()
660 store.close()
661 if opts.get('exact') and hex(n) != nodeid:
661 if opts.get('exact') and hex(n) != nodeid:
662 raise util.Abort(_('patch is damaged or loses information'))
662 raise util.Abort(_('patch is damaged or loses information'))
663 if n:
663 if n:
664 # i18n: refers to a short changeset id
664 # i18n: refers to a short changeset id
665 msg = _('created %s') % short(n)
665 msg = _('created %s') % short(n)
666 return (msg, n)
666 return (msg, n)
667 finally:
667 finally:
668 os.unlink(tmpname)
668 os.unlink(tmpname)
669
669
670 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
670 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
671 opts=None):
671 opts=None):
672 '''export changesets as hg patches.'''
672 '''export changesets as hg patches.'''
673
673
674 total = len(revs)
674 total = len(revs)
675 revwidth = max([len(str(rev)) for rev in revs])
675 revwidth = max([len(str(rev)) for rev in revs])
676 filemode = {}
676 filemode = {}
677
677
678 def single(rev, seqno, fp):
678 def single(rev, seqno, fp):
679 ctx = repo[rev]
679 ctx = repo[rev]
680 node = ctx.node()
680 node = ctx.node()
681 parents = [p.node() for p in ctx.parents() if p]
681 parents = [p.node() for p in ctx.parents() if p]
682 branch = ctx.branch()
682 branch = ctx.branch()
683 if switch_parent:
683 if switch_parent:
684 parents.reverse()
684 parents.reverse()
685 prev = (parents and parents[0]) or nullid
685 prev = (parents and parents[0]) or nullid
686
686
687 shouldclose = False
687 shouldclose = False
688 if not fp and len(template) > 0:
688 if not fp and len(template) > 0:
689 desc_lines = ctx.description().rstrip().split('\n')
689 desc_lines = ctx.description().rstrip().split('\n')
690 desc = desc_lines[0] #Commit always has a first line.
690 desc = desc_lines[0] #Commit always has a first line.
691 fp = makefileobj(repo, template, node, desc=desc, total=total,
691 fp = makefileobj(repo, template, node, desc=desc, total=total,
692 seqno=seqno, revwidth=revwidth, mode='wb',
692 seqno=seqno, revwidth=revwidth, mode='wb',
693 modemap=filemode)
693 modemap=filemode)
694 if fp != template:
694 if fp != template:
695 shouldclose = True
695 shouldclose = True
696 if fp and fp != sys.stdout and util.safehasattr(fp, 'name'):
696 if fp and fp != sys.stdout and util.safehasattr(fp, 'name'):
697 repo.ui.note("%s\n" % fp.name)
697 repo.ui.note("%s\n" % fp.name)
698
698
699 if not fp:
699 if not fp:
700 write = repo.ui.write
700 write = repo.ui.write
701 else:
701 else:
702 def write(s, **kw):
702 def write(s, **kw):
703 fp.write(s)
703 fp.write(s)
704
704
705
705
706 write("# HG changeset patch\n")
706 write("# HG changeset patch\n")
707 write("# User %s\n" % ctx.user())
707 write("# User %s\n" % ctx.user())
708 write("# Date %d %d\n" % ctx.date())
708 write("# Date %d %d\n" % ctx.date())
709 write("# %s\n" % util.datestr(ctx.date()))
709 write("# %s\n" % util.datestr(ctx.date()))
710 if branch and branch != 'default':
710 if branch and branch != 'default':
711 write("# Branch %s\n" % branch)
711 write("# Branch %s\n" % branch)
712 write("# Node ID %s\n" % hex(node))
712 write("# Node ID %s\n" % hex(node))
713 write("# Parent %s\n" % hex(prev))
713 write("# Parent %s\n" % hex(prev))
714 if len(parents) > 1:
714 if len(parents) > 1:
715 write("# Parent %s\n" % hex(parents[1]))
715 write("# Parent %s\n" % hex(parents[1]))
716 write(ctx.description().rstrip())
716 write(ctx.description().rstrip())
717 write("\n\n")
717 write("\n\n")
718
718
719 for chunk, label in patch.diffui(repo, prev, node, opts=opts):
719 for chunk, label in patch.diffui(repo, prev, node, opts=opts):
720 write(chunk, label=label)
720 write(chunk, label=label)
721
721
722 if shouldclose:
722 if shouldclose:
723 fp.close()
723 fp.close()
724
724
725 for seqno, rev in enumerate(revs):
725 for seqno, rev in enumerate(revs):
726 single(rev, seqno + 1, fp)
726 single(rev, seqno + 1, fp)
727
727
728 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
728 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
729 changes=None, stat=False, fp=None, prefix='',
729 changes=None, stat=False, fp=None, prefix='',
730 listsubrepos=False):
730 listsubrepos=False):
731 '''show diff or diffstat.'''
731 '''show diff or diffstat.'''
732 if fp is None:
732 if fp is None:
733 write = ui.write
733 write = ui.write
734 else:
734 else:
735 def write(s, **kw):
735 def write(s, **kw):
736 fp.write(s)
736 fp.write(s)
737
737
738 if stat:
738 if stat:
739 diffopts = diffopts.copy(context=0)
739 diffopts = diffopts.copy(context=0)
740 width = 80
740 width = 80
741 if not ui.plain():
741 if not ui.plain():
742 width = ui.termwidth()
742 width = ui.termwidth()
743 chunks = patch.diff(repo, node1, node2, match, changes, diffopts,
743 chunks = patch.diff(repo, node1, node2, match, changes, diffopts,
744 prefix=prefix)
744 prefix=prefix)
745 for chunk, label in patch.diffstatui(util.iterlines(chunks),
745 for chunk, label in patch.diffstatui(util.iterlines(chunks),
746 width=width,
746 width=width,
747 git=diffopts.git):
747 git=diffopts.git):
748 write(chunk, label=label)
748 write(chunk, label=label)
749 else:
749 else:
750 for chunk, label in patch.diffui(repo, node1, node2, match,
750 for chunk, label in patch.diffui(repo, node1, node2, match,
751 changes, diffopts, prefix=prefix):
751 changes, diffopts, prefix=prefix):
752 write(chunk, label=label)
752 write(chunk, label=label)
753
753
754 if listsubrepos:
754 if listsubrepos:
755 ctx1 = repo[node1]
755 ctx1 = repo[node1]
756 ctx2 = repo[node2]
756 ctx2 = repo[node2]
757 for subpath, sub in scmutil.itersubrepos(ctx1, ctx2):
757 for subpath, sub in scmutil.itersubrepos(ctx1, ctx2):
758 tempnode2 = node2
758 tempnode2 = node2
759 try:
759 try:
760 if node2 is not None:
760 if node2 is not None:
761 tempnode2 = ctx2.substate[subpath][1]
761 tempnode2 = ctx2.substate[subpath][1]
762 except KeyError:
762 except KeyError:
763 # A subrepo that existed in node1 was deleted between node1 and
763 # A subrepo that existed in node1 was deleted between node1 and
764 # node2 (inclusive). Thus, ctx2's substate won't contain that
764 # node2 (inclusive). Thus, ctx2's substate won't contain that
765 # subpath. The best we can do is to ignore it.
765 # subpath. The best we can do is to ignore it.
766 tempnode2 = None
766 tempnode2 = None
767 submatch = matchmod.narrowmatcher(subpath, match)
767 submatch = matchmod.narrowmatcher(subpath, match)
768 sub.diff(ui, diffopts, tempnode2, submatch, changes=changes,
768 sub.diff(ui, diffopts, tempnode2, submatch, changes=changes,
769 stat=stat, fp=fp, prefix=prefix)
769 stat=stat, fp=fp, prefix=prefix)
770
770
771 class changeset_printer(object):
771 class changeset_printer(object):
772 '''show changeset information when templating not requested.'''
772 '''show changeset information when templating not requested.'''
773
773
774 def __init__(self, ui, repo, patch, diffopts, buffered):
774 def __init__(self, ui, repo, patch, diffopts, buffered):
775 self.ui = ui
775 self.ui = ui
776 self.repo = repo
776 self.repo = repo
777 self.buffered = buffered
777 self.buffered = buffered
778 self.patch = patch
778 self.patch = patch
779 self.diffopts = diffopts
779 self.diffopts = diffopts
780 self.header = {}
780 self.header = {}
781 self.hunk = {}
781 self.hunk = {}
782 self.lastheader = None
782 self.lastheader = None
783 self.footer = None
783 self.footer = None
784
784
785 def flush(self, rev):
785 def flush(self, rev):
786 if rev in self.header:
786 if rev in self.header:
787 h = self.header[rev]
787 h = self.header[rev]
788 if h != self.lastheader:
788 if h != self.lastheader:
789 self.lastheader = h
789 self.lastheader = h
790 self.ui.write(h)
790 self.ui.write(h)
791 del self.header[rev]
791 del self.header[rev]
792 if rev in self.hunk:
792 if rev in self.hunk:
793 self.ui.write(self.hunk[rev])
793 self.ui.write(self.hunk[rev])
794 del self.hunk[rev]
794 del self.hunk[rev]
795 return 1
795 return 1
796 return 0
796 return 0
797
797
798 def close(self):
798 def close(self):
799 if self.footer:
799 if self.footer:
800 self.ui.write(self.footer)
800 self.ui.write(self.footer)
801
801
802 def show(self, ctx, copies=None, matchfn=None, **props):
802 def show(self, ctx, copies=None, matchfn=None, **props):
803 if self.buffered:
803 if self.buffered:
804 self.ui.pushbuffer()
804 self.ui.pushbuffer()
805 self._show(ctx, copies, matchfn, props)
805 self._show(ctx, copies, matchfn, props)
806 self.hunk[ctx.rev()] = self.ui.popbuffer(labeled=True)
806 self.hunk[ctx.rev()] = self.ui.popbuffer(labeled=True)
807 else:
807 else:
808 self._show(ctx, copies, matchfn, props)
808 self._show(ctx, copies, matchfn, props)
809
809
810 def _show(self, ctx, copies, matchfn, props):
810 def _show(self, ctx, copies, matchfn, props):
811 '''show a single changeset or file revision'''
811 '''show a single changeset or file revision'''
812 changenode = ctx.node()
812 changenode = ctx.node()
813 rev = ctx.rev()
813 rev = ctx.rev()
814
814
815 if self.ui.quiet:
815 if self.ui.quiet:
816 self.ui.write("%d:%s\n" % (rev, short(changenode)),
816 self.ui.write("%d:%s\n" % (rev, short(changenode)),
817 label='log.node')
817 label='log.node')
818 return
818 return
819
819
820 log = self.repo.changelog
820 log = self.repo.changelog
821 date = util.datestr(ctx.date())
821 date = util.datestr(ctx.date())
822
822
823 hexfunc = self.ui.debugflag and hex or short
823 hexfunc = self.ui.debugflag and hex or short
824
824
825 parents = [(p, hexfunc(log.node(p)))
825 parents = [(p, hexfunc(log.node(p)))
826 for p in self._meaningful_parentrevs(log, rev)]
826 for p in self._meaningful_parentrevs(log, rev)]
827
827
828 # i18n: column positioning for "hg log"
828 # i18n: column positioning for "hg log"
829 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)),
829 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)),
830 label='log.changeset changeset.%s' % ctx.phasestr())
830 label='log.changeset changeset.%s' % ctx.phasestr())
831
831
832 branch = ctx.branch()
832 branch = ctx.branch()
833 # don't show the default branch name
833 # don't show the default branch name
834 if branch != 'default':
834 if branch != 'default':
835 # i18n: column positioning for "hg log"
835 # i18n: column positioning for "hg log"
836 self.ui.write(_("branch: %s\n") % branch,
836 self.ui.write(_("branch: %s\n") % branch,
837 label='log.branch')
837 label='log.branch')
838 for bookmark in self.repo.nodebookmarks(changenode):
838 for bookmark in self.repo.nodebookmarks(changenode):
839 # i18n: column positioning for "hg log"
839 # i18n: column positioning for "hg log"
840 self.ui.write(_("bookmark: %s\n") % bookmark,
840 self.ui.write(_("bookmark: %s\n") % bookmark,
841 label='log.bookmark')
841 label='log.bookmark')
842 for tag in self.repo.nodetags(changenode):
842 for tag in self.repo.nodetags(changenode):
843 # i18n: column positioning for "hg log"
843 # i18n: column positioning for "hg log"
844 self.ui.write(_("tag: %s\n") % tag,
844 self.ui.write(_("tag: %s\n") % tag,
845 label='log.tag')
845 label='log.tag')
846 if self.ui.debugflag and ctx.phase():
846 if self.ui.debugflag and ctx.phase():
847 # i18n: column positioning for "hg log"
847 # i18n: column positioning for "hg log"
848 self.ui.write(_("phase: %s\n") % _(ctx.phasestr()),
848 self.ui.write(_("phase: %s\n") % _(ctx.phasestr()),
849 label='log.phase')
849 label='log.phase')
850 for parent in parents:
850 for parent in parents:
851 # i18n: column positioning for "hg log"
851 # i18n: column positioning for "hg log"
852 self.ui.write(_("parent: %d:%s\n") % parent,
852 self.ui.write(_("parent: %d:%s\n") % parent,
853 label='log.parent changeset.%s' % ctx.phasestr())
853 label='log.parent changeset.%s' % ctx.phasestr())
854
854
855 if self.ui.debugflag:
855 if self.ui.debugflag:
856 mnode = ctx.manifestnode()
856 mnode = ctx.manifestnode()
857 # i18n: column positioning for "hg log"
857 # i18n: column positioning for "hg log"
858 self.ui.write(_("manifest: %d:%s\n") %
858 self.ui.write(_("manifest: %d:%s\n") %
859 (self.repo.manifest.rev(mnode), hex(mnode)),
859 (self.repo.manifest.rev(mnode), hex(mnode)),
860 label='ui.debug log.manifest')
860 label='ui.debug log.manifest')
861 # i18n: column positioning for "hg log"
861 # i18n: column positioning for "hg log"
862 self.ui.write(_("user: %s\n") % ctx.user(),
862 self.ui.write(_("user: %s\n") % ctx.user(),
863 label='log.user')
863 label='log.user')
864 # i18n: column positioning for "hg log"
864 # i18n: column positioning for "hg log"
865 self.ui.write(_("date: %s\n") % date,
865 self.ui.write(_("date: %s\n") % date,
866 label='log.date')
866 label='log.date')
867
867
868 if self.ui.debugflag:
868 if self.ui.debugflag:
869 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
869 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
870 for key, value in zip([# i18n: column positioning for "hg log"
870 for key, value in zip([# i18n: column positioning for "hg log"
871 _("files:"),
871 _("files:"),
872 # i18n: column positioning for "hg log"
872 # i18n: column positioning for "hg log"
873 _("files+:"),
873 _("files+:"),
874 # i18n: column positioning for "hg log"
874 # i18n: column positioning for "hg log"
875 _("files-:")], files):
875 _("files-:")], files):
876 if value:
876 if value:
877 self.ui.write("%-12s %s\n" % (key, " ".join(value)),
877 self.ui.write("%-12s %s\n" % (key, " ".join(value)),
878 label='ui.debug log.files')
878 label='ui.debug log.files')
879 elif ctx.files() and self.ui.verbose:
879 elif ctx.files() and self.ui.verbose:
880 # i18n: column positioning for "hg log"
880 # i18n: column positioning for "hg log"
881 self.ui.write(_("files: %s\n") % " ".join(ctx.files()),
881 self.ui.write(_("files: %s\n") % " ".join(ctx.files()),
882 label='ui.note log.files')
882 label='ui.note log.files')
883 if copies and self.ui.verbose:
883 if copies and self.ui.verbose:
884 copies = ['%s (%s)' % c for c in copies]
884 copies = ['%s (%s)' % c for c in copies]
885 # i18n: column positioning for "hg log"
885 # i18n: column positioning for "hg log"
886 self.ui.write(_("copies: %s\n") % ' '.join(copies),
886 self.ui.write(_("copies: %s\n") % ' '.join(copies),
887 label='ui.note log.copies')
887 label='ui.note log.copies')
888
888
889 extra = ctx.extra()
889 extra = ctx.extra()
890 if extra and self.ui.debugflag:
890 if extra and self.ui.debugflag:
891 for key, value in sorted(extra.items()):
891 for key, value in sorted(extra.items()):
892 # i18n: column positioning for "hg log"
892 # i18n: column positioning for "hg log"
893 self.ui.write(_("extra: %s=%s\n")
893 self.ui.write(_("extra: %s=%s\n")
894 % (key, value.encode('string_escape')),
894 % (key, value.encode('string_escape')),
895 label='ui.debug log.extra')
895 label='ui.debug log.extra')
896
896
897 description = ctx.description().strip()
897 description = ctx.description().strip()
898 if description:
898 if description:
899 if self.ui.verbose:
899 if self.ui.verbose:
900 self.ui.write(_("description:\n"),
900 self.ui.write(_("description:\n"),
901 label='ui.note log.description')
901 label='ui.note log.description')
902 self.ui.write(description,
902 self.ui.write(description,
903 label='ui.note log.description')
903 label='ui.note log.description')
904 self.ui.write("\n\n")
904 self.ui.write("\n\n")
905 else:
905 else:
906 # i18n: column positioning for "hg log"
906 # i18n: column positioning for "hg log"
907 self.ui.write(_("summary: %s\n") %
907 self.ui.write(_("summary: %s\n") %
908 description.splitlines()[0],
908 description.splitlines()[0],
909 label='log.summary')
909 label='log.summary')
910 self.ui.write("\n")
910 self.ui.write("\n")
911
911
912 self.showpatch(changenode, matchfn)
912 self.showpatch(changenode, matchfn)
913
913
914 def showpatch(self, node, matchfn):
914 def showpatch(self, node, matchfn):
915 if not matchfn:
915 if not matchfn:
916 matchfn = self.patch
916 matchfn = self.patch
917 if matchfn:
917 if matchfn:
918 stat = self.diffopts.get('stat')
918 stat = self.diffopts.get('stat')
919 diff = self.diffopts.get('patch')
919 diff = self.diffopts.get('patch')
920 diffopts = patch.diffopts(self.ui, self.diffopts)
920 diffopts = patch.diffopts(self.ui, self.diffopts)
921 prev = self.repo.changelog.parents(node)[0]
921 prev = self.repo.changelog.parents(node)[0]
922 if stat:
922 if stat:
923 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
923 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
924 match=matchfn, stat=True)
924 match=matchfn, stat=True)
925 if diff:
925 if diff:
926 if stat:
926 if stat:
927 self.ui.write("\n")
927 self.ui.write("\n")
928 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
928 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
929 match=matchfn, stat=False)
929 match=matchfn, stat=False)
930 self.ui.write("\n")
930 self.ui.write("\n")
931
931
932 def _meaningful_parentrevs(self, log, rev):
932 def _meaningful_parentrevs(self, log, rev):
933 """Return list of meaningful (or all if debug) parentrevs for rev.
933 """Return list of meaningful (or all if debug) parentrevs for rev.
934
934
935 For merges (two non-nullrev revisions) both parents are meaningful.
935 For merges (two non-nullrev revisions) both parents are meaningful.
936 Otherwise the first parent revision is considered meaningful if it
936 Otherwise the first parent revision is considered meaningful if it
937 is not the preceding revision.
937 is not the preceding revision.
938 """
938 """
939 parents = log.parentrevs(rev)
939 parents = log.parentrevs(rev)
940 if not self.ui.debugflag and parents[1] == nullrev:
940 if not self.ui.debugflag and parents[1] == nullrev:
941 if parents[0] >= rev - 1:
941 if parents[0] >= rev - 1:
942 parents = []
942 parents = []
943 else:
943 else:
944 parents = [parents[0]]
944 parents = [parents[0]]
945 return parents
945 return parents
946
946
947
947
948 class changeset_templater(changeset_printer):
948 class changeset_templater(changeset_printer):
949 '''format changeset information.'''
949 '''format changeset information.'''
950
950
951 def __init__(self, ui, repo, patch, diffopts, tmpl, mapfile, buffered):
951 def __init__(self, ui, repo, patch, diffopts, tmpl, mapfile, buffered):
952 changeset_printer.__init__(self, ui, repo, patch, diffopts, buffered)
952 changeset_printer.__init__(self, ui, repo, patch, diffopts, buffered)
953 formatnode = ui.debugflag and (lambda x: x) or (lambda x: x[:12])
953 formatnode = ui.debugflag and (lambda x: x) or (lambda x: x[:12])
954 defaulttempl = {
954 defaulttempl = {
955 'parent': '{rev}:{node|formatnode} ',
955 'parent': '{rev}:{node|formatnode} ',
956 'manifest': '{rev}:{node|formatnode}',
956 'manifest': '{rev}:{node|formatnode}',
957 'file_copy': '{name} ({source})',
957 'file_copy': '{name} ({source})',
958 'extra': '{key}={value|stringescape}'
958 'extra': '{key}={value|stringescape}'
959 }
959 }
960 # filecopy is preserved for compatibility reasons
960 # filecopy is preserved for compatibility reasons
961 defaulttempl['filecopy'] = defaulttempl['file_copy']
961 defaulttempl['filecopy'] = defaulttempl['file_copy']
962 self.t = templater.templater(mapfile, {'formatnode': formatnode},
962 self.t = templater.templater(mapfile, {'formatnode': formatnode},
963 cache=defaulttempl)
963 cache=defaulttempl)
964 if tmpl:
964 if tmpl:
965 self.t.cache['changeset'] = tmpl
965 self.t.cache['changeset'] = tmpl
966
966
967 self.cache = {}
967 self.cache = {}
968
968
969 def _meaningful_parentrevs(self, ctx):
969 def _meaningful_parentrevs(self, ctx):
970 """Return list of meaningful (or all if debug) parentrevs for rev.
970 """Return list of meaningful (or all if debug) parentrevs for rev.
971 """
971 """
972 parents = ctx.parents()
972 parents = ctx.parents()
973 if len(parents) > 1:
973 if len(parents) > 1:
974 return parents
974 return parents
975 if self.ui.debugflag:
975 if self.ui.debugflag:
976 return [parents[0], self.repo['null']]
976 return [parents[0], self.repo['null']]
977 if parents[0].rev() >= ctx.rev() - 1:
977 if parents[0].rev() >= ctx.rev() - 1:
978 return []
978 return []
979 return parents
979 return parents
980
980
981 def _show(self, ctx, copies, matchfn, props):
981 def _show(self, ctx, copies, matchfn, props):
982 '''show a single changeset or file revision'''
982 '''show a single changeset or file revision'''
983
983
984 showlist = templatekw.showlist
984 showlist = templatekw.showlist
985
985
986 # showparents() behaviour depends on ui trace level which
986 # showparents() behaviour depends on ui trace level which
987 # causes unexpected behaviours at templating level and makes
987 # causes unexpected behaviours at templating level and makes
988 # it harder to extract it in a standalone function. Its
988 # it harder to extract it in a standalone function. Its
989 # behaviour cannot be changed so leave it here for now.
989 # behaviour cannot be changed so leave it here for now.
990 def showparents(**args):
990 def showparents(**args):
991 ctx = args['ctx']
991 ctx = args['ctx']
992 parents = [[('rev', p.rev()), ('node', p.hex())]
992 parents = [[('rev', p.rev()), ('node', p.hex())]
993 for p in self._meaningful_parentrevs(ctx)]
993 for p in self._meaningful_parentrevs(ctx)]
994 return showlist('parent', parents, **args)
994 return showlist('parent', parents, **args)
995
995
996 props = props.copy()
996 props = props.copy()
997 props.update(templatekw.keywords)
997 props.update(templatekw.keywords)
998 props['parents'] = showparents
998 props['parents'] = showparents
999 props['templ'] = self.t
999 props['templ'] = self.t
1000 props['ctx'] = ctx
1000 props['ctx'] = ctx
1001 props['repo'] = self.repo
1001 props['repo'] = self.repo
1002 props['revcache'] = {'copies': copies}
1002 props['revcache'] = {'copies': copies}
1003 props['cache'] = self.cache
1003 props['cache'] = self.cache
1004
1004
1005 # find correct templates for current mode
1005 # find correct templates for current mode
1006
1006
1007 tmplmodes = [
1007 tmplmodes = [
1008 (True, None),
1008 (True, None),
1009 (self.ui.verbose, 'verbose'),
1009 (self.ui.verbose, 'verbose'),
1010 (self.ui.quiet, 'quiet'),
1010 (self.ui.quiet, 'quiet'),
1011 (self.ui.debugflag, 'debug'),
1011 (self.ui.debugflag, 'debug'),
1012 ]
1012 ]
1013
1013
1014 types = {'header': '', 'footer':'', 'changeset': 'changeset'}
1014 types = {'header': '', 'footer':'', 'changeset': 'changeset'}
1015 for mode, postfix in tmplmodes:
1015 for mode, postfix in tmplmodes:
1016 for type in types:
1016 for type in types:
1017 cur = postfix and ('%s_%s' % (type, postfix)) or type
1017 cur = postfix and ('%s_%s' % (type, postfix)) or type
1018 if mode and cur in self.t:
1018 if mode and cur in self.t:
1019 types[type] = cur
1019 types[type] = cur
1020
1020
1021 try:
1021 try:
1022
1022
1023 # write header
1023 # write header
1024 if types['header']:
1024 if types['header']:
1025 h = templater.stringify(self.t(types['header'], **props))
1025 h = templater.stringify(self.t(types['header'], **props))
1026 if self.buffered:
1026 if self.buffered:
1027 self.header[ctx.rev()] = h
1027 self.header[ctx.rev()] = h
1028 else:
1028 else:
1029 if self.lastheader != h:
1029 if self.lastheader != h:
1030 self.lastheader = h
1030 self.lastheader = h
1031 self.ui.write(h)
1031 self.ui.write(h)
1032
1032
1033 # write changeset metadata, then patch if requested
1033 # write changeset metadata, then patch if requested
1034 key = types['changeset']
1034 key = types['changeset']
1035 self.ui.write(templater.stringify(self.t(key, **props)))
1035 self.ui.write(templater.stringify(self.t(key, **props)))
1036 self.showpatch(ctx.node(), matchfn)
1036 self.showpatch(ctx.node(), matchfn)
1037
1037
1038 if types['footer']:
1038 if types['footer']:
1039 if not self.footer:
1039 if not self.footer:
1040 self.footer = templater.stringify(self.t(types['footer'],
1040 self.footer = templater.stringify(self.t(types['footer'],
1041 **props))
1041 **props))
1042
1042
1043 except KeyError, inst:
1043 except KeyError, inst:
1044 msg = _("%s: no key named '%s'")
1044 msg = _("%s: no key named '%s'")
1045 raise util.Abort(msg % (self.t.mapfile, inst.args[0]))
1045 raise util.Abort(msg % (self.t.mapfile, inst.args[0]))
1046 except SyntaxError, inst:
1046 except SyntaxError, inst:
1047 raise util.Abort('%s: %s' % (self.t.mapfile, inst.args[0]))
1047 raise util.Abort('%s: %s' % (self.t.mapfile, inst.args[0]))
1048
1048
1049 def gettemplate(ui, tmpl, style):
1049 def gettemplate(ui, tmpl, style):
1050 """
1050 """
1051 Find the template matching the given template spec or style.
1051 Find the template matching the given template spec or style.
1052 """
1052 """
1053
1053
1054 # ui settings
1054 # ui settings
1055 if not tmpl and not style:
1055 if not tmpl and not style:
1056 tmpl = ui.config('ui', 'logtemplate')
1056 tmpl = ui.config('ui', 'logtemplate')
1057 if tmpl:
1057 if tmpl:
1058 try:
1058 try:
1059 tmpl = templater.parsestring(tmpl)
1059 tmpl = templater.parsestring(tmpl)
1060 except SyntaxError:
1060 except SyntaxError:
1061 tmpl = templater.parsestring(tmpl, quoted=False)
1061 tmpl = templater.parsestring(tmpl, quoted=False)
1062 return tmpl, None
1062 return tmpl, None
1063 else:
1063 else:
1064 style = util.expandpath(ui.config('ui', 'style', ''))
1064 style = util.expandpath(ui.config('ui', 'style', ''))
1065
1065
1066 if style:
1066 if style:
1067 mapfile = style
1067 mapfile = style
1068 if not os.path.split(mapfile)[0]:
1068 if not os.path.split(mapfile)[0]:
1069 mapname = (templater.templatepath('map-cmdline.' + mapfile)
1069 mapname = (templater.templatepath('map-cmdline.' + mapfile)
1070 or templater.templatepath(mapfile))
1070 or templater.templatepath(mapfile))
1071 if mapname:
1071 if mapname:
1072 mapfile = mapname
1072 mapfile = mapname
1073 return None, mapfile
1073 return None, mapfile
1074
1074
1075 if not tmpl:
1075 if not tmpl:
1076 return None, None
1076 return None, None
1077
1077
1078 # looks like a literal template?
1078 # looks like a literal template?
1079 if '{' in tmpl:
1079 if '{' in tmpl:
1080 return tmpl, None
1080 return tmpl, None
1081
1081
1082 # perhaps a stock style?
1082 # perhaps a stock style?
1083 if not os.path.split(tmpl)[0]:
1083 if not os.path.split(tmpl)[0]:
1084 mapname = (templater.templatepath('map-cmdline.' + tmpl)
1084 mapname = (templater.templatepath('map-cmdline.' + tmpl)
1085 or templater.templatepath(tmpl))
1085 or templater.templatepath(tmpl))
1086 if mapname and os.path.isfile(mapname):
1086 if mapname and os.path.isfile(mapname):
1087 return None, mapname
1087 return None, mapname
1088
1088
1089 # perhaps it's a reference to [templates]
1089 # perhaps it's a reference to [templates]
1090 t = ui.config('templates', tmpl)
1090 t = ui.config('templates', tmpl)
1091 if t:
1091 if t:
1092 try:
1092 try:
1093 tmpl = templater.parsestring(t)
1093 tmpl = templater.parsestring(t)
1094 except SyntaxError:
1094 except SyntaxError:
1095 tmpl = templater.parsestring(t, quoted=False)
1095 tmpl = templater.parsestring(t, quoted=False)
1096 return tmpl, None
1096 return tmpl, None
1097
1097
1098 # perhaps it's a path to a map or a template
1098 # perhaps it's a path to a map or a template
1099 if ('/' in tmpl or '\\' in tmpl) and os.path.isfile(tmpl):
1099 if ('/' in tmpl or '\\' in tmpl) and os.path.isfile(tmpl):
1100 # is it a mapfile for a style?
1100 # is it a mapfile for a style?
1101 if os.path.basename(tmpl).startswith("map-"):
1101 if os.path.basename(tmpl).startswith("map-"):
1102 return None, os.path.realpath(tmpl)
1102 return None, os.path.realpath(tmpl)
1103 tmpl = open(tmpl).read()
1103 tmpl = open(tmpl).read()
1104 return tmpl, None
1104 return tmpl, None
1105
1105
1106 # constant string?
1106 # constant string?
1107 return tmpl, None
1107 return tmpl, None
1108
1108
1109 def show_changeset(ui, repo, opts, buffered=False):
1109 def show_changeset(ui, repo, opts, buffered=False):
1110 """show one changeset using template or regular display.
1110 """show one changeset using template or regular display.
1111
1111
1112 Display format will be the first non-empty hit of:
1112 Display format will be the first non-empty hit of:
1113 1. option 'template'
1113 1. option 'template'
1114 2. option 'style'
1114 2. option 'style'
1115 3. [ui] setting 'logtemplate'
1115 3. [ui] setting 'logtemplate'
1116 4. [ui] setting 'style'
1116 4. [ui] setting 'style'
1117 If all of these values are either the unset or the empty string,
1117 If all of these values are either the unset or the empty string,
1118 regular display via changeset_printer() is done.
1118 regular display via changeset_printer() is done.
1119 """
1119 """
1120 # options
1120 # options
1121 patch = None
1121 patch = None
1122 if opts.get('patch') or opts.get('stat'):
1122 if opts.get('patch') or opts.get('stat'):
1123 patch = scmutil.matchall(repo)
1123 patch = scmutil.matchall(repo)
1124
1124
1125 tmpl, mapfile = gettemplate(ui, opts.get('template'), opts.get('style'))
1125 tmpl, mapfile = gettemplate(ui, opts.get('template'), opts.get('style'))
1126
1126
1127 if not tmpl and not mapfile:
1127 if not tmpl and not mapfile:
1128 return changeset_printer(ui, repo, patch, opts, buffered)
1128 return changeset_printer(ui, repo, patch, opts, buffered)
1129
1129
1130 try:
1130 try:
1131 t = changeset_templater(ui, repo, patch, opts, tmpl, mapfile, buffered)
1131 t = changeset_templater(ui, repo, patch, opts, tmpl, mapfile, buffered)
1132 except SyntaxError, inst:
1132 except SyntaxError, inst:
1133 raise util.Abort(inst.args[0])
1133 raise util.Abort(inst.args[0])
1134 return t
1134 return t
1135
1135
1136 def showmarker(ui, marker):
1136 def showmarker(ui, marker):
1137 """utility function to display obsolescence marker in a readable way
1137 """utility function to display obsolescence marker in a readable way
1138
1138
1139 To be used by debug function."""
1139 To be used by debug function."""
1140 ui.write(hex(marker.precnode()))
1140 ui.write(hex(marker.precnode()))
1141 for repl in marker.succnodes():
1141 for repl in marker.succnodes():
1142 ui.write(' ')
1142 ui.write(' ')
1143 ui.write(hex(repl))
1143 ui.write(hex(repl))
1144 ui.write(' %X ' % marker._data[2])
1144 ui.write(' %X ' % marker._data[2])
1145 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
1145 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
1146 sorted(marker.metadata().items()))))
1146 sorted(marker.metadata().items()))))
1147 ui.write('\n')
1147 ui.write('\n')
1148
1148
1149 def finddate(ui, repo, date):
1149 def finddate(ui, repo, date):
1150 """Find the tipmost changeset that matches the given date spec"""
1150 """Find the tipmost changeset that matches the given date spec"""
1151
1151
1152 df = util.matchdate(date)
1152 df = util.matchdate(date)
1153 m = scmutil.matchall(repo)
1153 m = scmutil.matchall(repo)
1154 results = {}
1154 results = {}
1155
1155
1156 def prep(ctx, fns):
1156 def prep(ctx, fns):
1157 d = ctx.date()
1157 d = ctx.date()
1158 if df(d[0]):
1158 if df(d[0]):
1159 results[ctx.rev()] = d
1159 results[ctx.rev()] = d
1160
1160
1161 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
1161 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
1162 rev = ctx.rev()
1162 rev = ctx.rev()
1163 if rev in results:
1163 if rev in results:
1164 ui.status(_("found revision %s from %s\n") %
1164 ui.status(_("found revision %s from %s\n") %
1165 (rev, util.datestr(results[rev])))
1165 (rev, util.datestr(results[rev])))
1166 return str(rev)
1166 return str(rev)
1167
1167
1168 raise util.Abort(_("revision matching date not found"))
1168 raise util.Abort(_("revision matching date not found"))
1169
1169
1170 def increasingwindows(windowsize=8, sizelimit=512):
1170 def increasingwindows(windowsize=8, sizelimit=512):
1171 while True:
1171 while True:
1172 yield windowsize
1172 yield windowsize
1173 if windowsize < sizelimit:
1173 if windowsize < sizelimit:
1174 windowsize *= 2
1174 windowsize *= 2
1175
1175
1176 class FileWalkError(Exception):
1176 class FileWalkError(Exception):
1177 pass
1177 pass
1178
1178
1179 def walkfilerevs(repo, match, follow, revs, fncache):
1179 def walkfilerevs(repo, match, follow, revs, fncache):
1180 '''Walks the file history for the matched files.
1180 '''Walks the file history for the matched files.
1181
1181
1182 Returns the changeset revs that are involved in the file history.
1182 Returns the changeset revs that are involved in the file history.
1183
1183
1184 Throws FileWalkError if the file history can't be walked using
1184 Throws FileWalkError if the file history can't be walked using
1185 filelogs alone.
1185 filelogs alone.
1186 '''
1186 '''
1187 wanted = set()
1187 wanted = set()
1188 copies = []
1188 copies = []
1189 minrev, maxrev = min(revs), max(revs)
1189 minrev, maxrev = min(revs), max(revs)
1190 def filerevgen(filelog, last):
1190 def filerevgen(filelog, last):
1191 """
1191 """
1192 Only files, no patterns. Check the history of each file.
1192 Only files, no patterns. Check the history of each file.
1193
1193
1194 Examines filelog entries within minrev, maxrev linkrev range
1194 Examines filelog entries within minrev, maxrev linkrev range
1195 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
1195 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
1196 tuples in backwards order
1196 tuples in backwards order
1197 """
1197 """
1198 cl_count = len(repo)
1198 cl_count = len(repo)
1199 revs = []
1199 revs = []
1200 for j in xrange(0, last + 1):
1200 for j in xrange(0, last + 1):
1201 linkrev = filelog.linkrev(j)
1201 linkrev = filelog.linkrev(j)
1202 if linkrev < minrev:
1202 if linkrev < minrev:
1203 continue
1203 continue
1204 # only yield rev for which we have the changelog, it can
1204 # only yield rev for which we have the changelog, it can
1205 # happen while doing "hg log" during a pull or commit
1205 # happen while doing "hg log" during a pull or commit
1206 if linkrev >= cl_count:
1206 if linkrev >= cl_count:
1207 break
1207 break
1208
1208
1209 parentlinkrevs = []
1209 parentlinkrevs = []
1210 for p in filelog.parentrevs(j):
1210 for p in filelog.parentrevs(j):
1211 if p != nullrev:
1211 if p != nullrev:
1212 parentlinkrevs.append(filelog.linkrev(p))
1212 parentlinkrevs.append(filelog.linkrev(p))
1213 n = filelog.node(j)
1213 n = filelog.node(j)
1214 revs.append((linkrev, parentlinkrevs,
1214 revs.append((linkrev, parentlinkrevs,
1215 follow and filelog.renamed(n)))
1215 follow and filelog.renamed(n)))
1216
1216
1217 return reversed(revs)
1217 return reversed(revs)
1218 def iterfiles():
1218 def iterfiles():
1219 pctx = repo['.']
1219 pctx = repo['.']
1220 for filename in match.files():
1220 for filename in match.files():
1221 if follow:
1221 if follow:
1222 if filename not in pctx:
1222 if filename not in pctx:
1223 raise util.Abort(_('cannot follow file not in parent '
1223 raise util.Abort(_('cannot follow file not in parent '
1224 'revision: "%s"') % filename)
1224 'revision: "%s"') % filename)
1225 yield filename, pctx[filename].filenode()
1225 yield filename, pctx[filename].filenode()
1226 else:
1226 else:
1227 yield filename, None
1227 yield filename, None
1228 for filename_node in copies:
1228 for filename_node in copies:
1229 yield filename_node
1229 yield filename_node
1230
1230
1231 for file_, node in iterfiles():
1231 for file_, node in iterfiles():
1232 filelog = repo.file(file_)
1232 filelog = repo.file(file_)
1233 if not len(filelog):
1233 if not len(filelog):
1234 if node is None:
1234 if node is None:
1235 # A zero count may be a directory or deleted file, so
1235 # A zero count may be a directory or deleted file, so
1236 # try to find matching entries on the slow path.
1236 # try to find matching entries on the slow path.
1237 if follow:
1237 if follow:
1238 raise util.Abort(
1238 raise util.Abort(
1239 _('cannot follow nonexistent file: "%s"') % file_)
1239 _('cannot follow nonexistent file: "%s"') % file_)
1240 raise FileWalkError("Cannot walk via filelog")
1240 raise FileWalkError("Cannot walk via filelog")
1241 else:
1241 else:
1242 continue
1242 continue
1243
1243
1244 if node is None:
1244 if node is None:
1245 last = len(filelog) - 1
1245 last = len(filelog) - 1
1246 else:
1246 else:
1247 last = filelog.rev(node)
1247 last = filelog.rev(node)
1248
1248
1249
1249
1250 # keep track of all ancestors of the file
1250 # keep track of all ancestors of the file
1251 ancestors = set([filelog.linkrev(last)])
1251 ancestors = set([filelog.linkrev(last)])
1252
1252
1253 # iterate from latest to oldest revision
1253 # iterate from latest to oldest revision
1254 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
1254 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
1255 if not follow:
1255 if not follow:
1256 if rev > maxrev:
1256 if rev > maxrev:
1257 continue
1257 continue
1258 else:
1258 else:
1259 # Note that last might not be the first interesting
1259 # Note that last might not be the first interesting
1260 # rev to us:
1260 # rev to us:
1261 # if the file has been changed after maxrev, we'll
1261 # if the file has been changed after maxrev, we'll
1262 # have linkrev(last) > maxrev, and we still need
1262 # have linkrev(last) > maxrev, and we still need
1263 # to explore the file graph
1263 # to explore the file graph
1264 if rev not in ancestors:
1264 if rev not in ancestors:
1265 continue
1265 continue
1266 # XXX insert 1327 fix here
1266 # XXX insert 1327 fix here
1267 if flparentlinkrevs:
1267 if flparentlinkrevs:
1268 ancestors.update(flparentlinkrevs)
1268 ancestors.update(flparentlinkrevs)
1269
1269
1270 fncache.setdefault(rev, []).append(file_)
1270 fncache.setdefault(rev, []).append(file_)
1271 wanted.add(rev)
1271 wanted.add(rev)
1272 if copied:
1272 if copied:
1273 copies.append(copied)
1273 copies.append(copied)
1274
1274
1275 return wanted
1275 return wanted
1276
1276
1277 def walkchangerevs(repo, match, opts, prepare):
1277 def walkchangerevs(repo, match, opts, prepare):
1278 '''Iterate over files and the revs in which they changed.
1278 '''Iterate over files and the revs in which they changed.
1279
1279
1280 Callers most commonly need to iterate backwards over the history
1280 Callers most commonly need to iterate backwards over the history
1281 in which they are interested. Doing so has awful (quadratic-looking)
1281 in which they are interested. Doing so has awful (quadratic-looking)
1282 performance, so we use iterators in a "windowed" way.
1282 performance, so we use iterators in a "windowed" way.
1283
1283
1284 We walk a window of revisions in the desired order. Within the
1284 We walk a window of revisions in the desired order. Within the
1285 window, we first walk forwards to gather data, then in the desired
1285 window, we first walk forwards to gather data, then in the desired
1286 order (usually backwards) to display it.
1286 order (usually backwards) to display it.
1287
1287
1288 This function returns an iterator yielding contexts. Before
1288 This function returns an iterator yielding contexts. Before
1289 yielding each context, the iterator will first call the prepare
1289 yielding each context, the iterator will first call the prepare
1290 function on each context in the window in forward order.'''
1290 function on each context in the window in forward order.'''
1291
1291
1292 follow = opts.get('follow') or opts.get('follow_first')
1292 follow = opts.get('follow') or opts.get('follow_first')
1293
1293
1294 if opts.get('rev'):
1294 if opts.get('rev'):
1295 revs = scmutil.revrange(repo, opts.get('rev'))
1295 revs = scmutil.revrange(repo, opts.get('rev'))
1296 elif follow:
1296 elif follow:
1297 revs = repo.revs('reverse(:.)')
1297 revs = repo.revs('reverse(:.)')
1298 else:
1298 else:
1299 revs = revset.baseset(repo)
1299 revs = revset.baseset(repo)
1300 revs.reverse()
1300 revs.reverse()
1301 if not revs:
1301 if not revs:
1302 return []
1302 return []
1303 wanted = set()
1303 wanted = set()
1304 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1304 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1305 fncache = {}
1305 fncache = {}
1306 change = repo.changectx
1306 change = repo.changectx
1307
1307
1308 # First step is to fill wanted, the set of revisions that we want to yield.
1308 # First step is to fill wanted, the set of revisions that we want to yield.
1309 # When it does not induce extra cost, we also fill fncache for revisions in
1309 # When it does not induce extra cost, we also fill fncache for revisions in
1310 # wanted: a cache of filenames that were changed (ctx.files()) and that
1310 # wanted: a cache of filenames that were changed (ctx.files()) and that
1311 # match the file filtering conditions.
1311 # match the file filtering conditions.
1312
1312
1313 if not slowpath and not match.files():
1313 if not slowpath and not match.files():
1314 # No files, no patterns. Display all revs.
1314 # No files, no patterns. Display all revs.
1315 wanted = revs
1315 wanted = revs
1316
1316
1317 if not slowpath and match.files():
1317 if not slowpath and match.files():
1318 # We only have to read through the filelog to find wanted revisions
1318 # We only have to read through the filelog to find wanted revisions
1319
1319
1320 try:
1320 try:
1321 wanted = walkfilerevs(repo, match, follow, revs, fncache)
1321 wanted = walkfilerevs(repo, match, follow, revs, fncache)
1322 except FileWalkError:
1322 except FileWalkError:
1323 slowpath = True
1323 slowpath = True
1324
1324
1325 # We decided to fall back to the slowpath because at least one
1325 # We decided to fall back to the slowpath because at least one
1326 # of the paths was not a file. Check to see if at least one of them
1326 # of the paths was not a file. Check to see if at least one of them
1327 # existed in history, otherwise simply return
1327 # existed in history, otherwise simply return
1328 for path in match.files():
1328 for path in match.files():
1329 if path == '.' or path in repo.store:
1329 if path == '.' or path in repo.store:
1330 break
1330 break
1331 else:
1331 else:
1332 return []
1332 return []
1333
1333
1334 if slowpath:
1334 if slowpath:
1335 # We have to read the changelog to match filenames against
1335 # We have to read the changelog to match filenames against
1336 # changed files
1336 # changed files
1337
1337
1338 if follow:
1338 if follow:
1339 raise util.Abort(_('can only follow copies/renames for explicit '
1339 raise util.Abort(_('can only follow copies/renames for explicit '
1340 'filenames'))
1340 'filenames'))
1341
1341
1342 # The slow path checks files modified in every changeset.
1342 # The slow path checks files modified in every changeset.
1343 # This is really slow on large repos, so compute the set lazily.
1343 # This is really slow on large repos, so compute the set lazily.
1344 class lazywantedset(object):
1344 class lazywantedset(object):
1345 def __init__(self):
1345 def __init__(self):
1346 self.set = set()
1346 self.set = set()
1347 self.revs = set(revs)
1347 self.revs = set(revs)
1348
1348
1349 # No need to worry about locality here because it will be accessed
1349 # No need to worry about locality here because it will be accessed
1350 # in the same order as the increasing window below.
1350 # in the same order as the increasing window below.
1351 def __contains__(self, value):
1351 def __contains__(self, value):
1352 if value in self.set:
1352 if value in self.set:
1353 return True
1353 return True
1354 elif not value in self.revs:
1354 elif not value in self.revs:
1355 return False
1355 return False
1356 else:
1356 else:
1357 self.revs.discard(value)
1357 self.revs.discard(value)
1358 ctx = change(value)
1358 ctx = change(value)
1359 matches = filter(match, ctx.files())
1359 matches = filter(match, ctx.files())
1360 if matches:
1360 if matches:
1361 fncache[value] = matches
1361 fncache[value] = matches
1362 self.set.add(value)
1362 self.set.add(value)
1363 return True
1363 return True
1364 return False
1364 return False
1365
1365
1366 def discard(self, value):
1366 def discard(self, value):
1367 self.revs.discard(value)
1367 self.revs.discard(value)
1368 self.set.discard(value)
1368 self.set.discard(value)
1369
1369
1370 wanted = lazywantedset()
1370 wanted = lazywantedset()
1371
1371
1372 class followfilter(object):
1372 class followfilter(object):
1373 def __init__(self, onlyfirst=False):
1373 def __init__(self, onlyfirst=False):
1374 self.startrev = nullrev
1374 self.startrev = nullrev
1375 self.roots = set()
1375 self.roots = set()
1376 self.onlyfirst = onlyfirst
1376 self.onlyfirst = onlyfirst
1377
1377
1378 def match(self, rev):
1378 def match(self, rev):
1379 def realparents(rev):
1379 def realparents(rev):
1380 if self.onlyfirst:
1380 if self.onlyfirst:
1381 return repo.changelog.parentrevs(rev)[0:1]
1381 return repo.changelog.parentrevs(rev)[0:1]
1382 else:
1382 else:
1383 return filter(lambda x: x != nullrev,
1383 return filter(lambda x: x != nullrev,
1384 repo.changelog.parentrevs(rev))
1384 repo.changelog.parentrevs(rev))
1385
1385
1386 if self.startrev == nullrev:
1386 if self.startrev == nullrev:
1387 self.startrev = rev
1387 self.startrev = rev
1388 return True
1388 return True
1389
1389
1390 if rev > self.startrev:
1390 if rev > self.startrev:
1391 # forward: all descendants
1391 # forward: all descendants
1392 if not self.roots:
1392 if not self.roots:
1393 self.roots.add(self.startrev)
1393 self.roots.add(self.startrev)
1394 for parent in realparents(rev):
1394 for parent in realparents(rev):
1395 if parent in self.roots:
1395 if parent in self.roots:
1396 self.roots.add(rev)
1396 self.roots.add(rev)
1397 return True
1397 return True
1398 else:
1398 else:
1399 # backwards: all parents
1399 # backwards: all parents
1400 if not self.roots:
1400 if not self.roots:
1401 self.roots.update(realparents(self.startrev))
1401 self.roots.update(realparents(self.startrev))
1402 if rev in self.roots:
1402 if rev in self.roots:
1403 self.roots.remove(rev)
1403 self.roots.remove(rev)
1404 self.roots.update(realparents(rev))
1404 self.roots.update(realparents(rev))
1405 return True
1405 return True
1406
1406
1407 return False
1407 return False
1408
1408
1409 # it might be worthwhile to do this in the iterator if the rev range
1409 # it might be worthwhile to do this in the iterator if the rev range
1410 # is descending and the prune args are all within that range
1410 # is descending and the prune args are all within that range
1411 for rev in opts.get('prune', ()):
1411 for rev in opts.get('prune', ()):
1412 rev = repo[rev].rev()
1412 rev = repo[rev].rev()
1413 ff = followfilter()
1413 ff = followfilter()
1414 stop = min(revs[0], revs[-1])
1414 stop = min(revs[0], revs[-1])
1415 for x in xrange(rev, stop - 1, -1):
1415 for x in xrange(rev, stop - 1, -1):
1416 if ff.match(x):
1416 if ff.match(x):
1417 wanted = wanted - [x]
1417 wanted = wanted - [x]
1418
1418
1419 # Now that wanted is correctly initialized, we can iterate over the
1419 # Now that wanted is correctly initialized, we can iterate over the
1420 # revision range, yielding only revisions in wanted.
1420 # revision range, yielding only revisions in wanted.
1421 def iterate():
1421 def iterate():
1422 if follow and not match.files():
1422 if follow and not match.files():
1423 ff = followfilter(onlyfirst=opts.get('follow_first'))
1423 ff = followfilter(onlyfirst=opts.get('follow_first'))
1424 def want(rev):
1424 def want(rev):
1425 return ff.match(rev) and rev in wanted
1425 return ff.match(rev) and rev in wanted
1426 else:
1426 else:
1427 def want(rev):
1427 def want(rev):
1428 return rev in wanted
1428 return rev in wanted
1429
1429
1430 it = iter(revs)
1430 it = iter(revs)
1431 stopiteration = False
1431 stopiteration = False
1432 for windowsize in increasingwindows():
1432 for windowsize in increasingwindows():
1433 nrevs = []
1433 nrevs = []
1434 for i in xrange(windowsize):
1434 for i in xrange(windowsize):
1435 try:
1435 try:
1436 rev = it.next()
1436 rev = it.next()
1437 if want(rev):
1437 if want(rev):
1438 nrevs.append(rev)
1438 nrevs.append(rev)
1439 except (StopIteration):
1439 except (StopIteration):
1440 stopiteration = True
1440 stopiteration = True
1441 break
1441 break
1442 for rev in sorted(nrevs):
1442 for rev in sorted(nrevs):
1443 fns = fncache.get(rev)
1443 fns = fncache.get(rev)
1444 ctx = change(rev)
1444 ctx = change(rev)
1445 if not fns:
1445 if not fns:
1446 def fns_generator():
1446 def fns_generator():
1447 for f in ctx.files():
1447 for f in ctx.files():
1448 if match(f):
1448 if match(f):
1449 yield f
1449 yield f
1450 fns = fns_generator()
1450 fns = fns_generator()
1451 prepare(ctx, fns)
1451 prepare(ctx, fns)
1452 for rev in nrevs:
1452 for rev in nrevs:
1453 yield change(rev)
1453 yield change(rev)
1454
1454
1455 if stopiteration:
1455 if stopiteration:
1456 break
1456 break
1457
1457
1458 return iterate()
1458 return iterate()
1459
1459
1460 def _makegraphfilematcher(repo, pats, followfirst):
1460 def _makegraphfilematcher(repo, pats, followfirst):
1461 # When displaying a revision with --patch --follow FILE, we have
1461 # When displaying a revision with --patch --follow FILE, we have
1462 # to know which file of the revision must be diffed. With
1462 # to know which file of the revision must be diffed. With
1463 # --follow, we want the names of the ancestors of FILE in the
1463 # --follow, we want the names of the ancestors of FILE in the
1464 # revision, stored in "fcache". "fcache" is populated by
1464 # revision, stored in "fcache". "fcache" is populated by
1465 # reproducing the graph traversal already done by --follow revset
1465 # reproducing the graph traversal already done by --follow revset
1466 # and relating linkrevs to file names (which is not "correct" but
1466 # and relating linkrevs to file names (which is not "correct" but
1467 # good enough).
1467 # good enough).
1468 fcache = {}
1468 fcache = {}
1469 fcacheready = [False]
1469 fcacheready = [False]
1470 pctx = repo['.']
1470 pctx = repo['.']
1471 wctx = repo[None]
1471 wctx = repo[None]
1472
1472
1473 def populate():
1473 def populate():
1474 for fn in pats:
1474 for fn in pats:
1475 for i in ((pctx[fn],), pctx[fn].ancestors(followfirst=followfirst)):
1475 for i in ((pctx[fn],), pctx[fn].ancestors(followfirst=followfirst)):
1476 for c in i:
1476 for c in i:
1477 fcache.setdefault(c.linkrev(), set()).add(c.path())
1477 fcache.setdefault(c.linkrev(), set()).add(c.path())
1478
1478
1479 def filematcher(rev):
1479 def filematcher(rev):
1480 if not fcacheready[0]:
1480 if not fcacheready[0]:
1481 # Lazy initialization
1481 # Lazy initialization
1482 fcacheready[0] = True
1482 fcacheready[0] = True
1483 populate()
1483 populate()
1484 return scmutil.match(wctx, fcache.get(rev, []), default='path')
1484 return scmutil.match(wctx, fcache.get(rev, []), default='path')
1485
1485
1486 return filematcher
1486 return filematcher
1487
1487
1488 def _makegraphlogrevset(repo, pats, opts, revs):
1488 def _makegraphlogrevset(repo, pats, opts, revs):
1489 """Return (expr, filematcher) where expr is a revset string built
1489 """Return (expr, filematcher) where expr is a revset string built
1490 from log options and file patterns or None. If --stat or --patch
1490 from log options and file patterns or None. If --stat or --patch
1491 are not passed filematcher is None. Otherwise it is a callable
1491 are not passed filematcher is None. Otherwise it is a callable
1492 taking a revision number and returning a match objects filtering
1492 taking a revision number and returning a match objects filtering
1493 the files to be detailed when displaying the revision.
1493 the files to be detailed when displaying the revision.
1494 """
1494 """
1495 opt2revset = {
1495 opt2revset = {
1496 'no_merges': ('not merge()', None),
1496 'no_merges': ('not merge()', None),
1497 'only_merges': ('merge()', None),
1497 'only_merges': ('merge()', None),
1498 '_ancestors': ('ancestors(%(val)s)', None),
1498 '_ancestors': ('ancestors(%(val)s)', None),
1499 '_fancestors': ('_firstancestors(%(val)s)', None),
1499 '_fancestors': ('_firstancestors(%(val)s)', None),
1500 '_descendants': ('descendants(%(val)s)', None),
1500 '_descendants': ('descendants(%(val)s)', None),
1501 '_fdescendants': ('_firstdescendants(%(val)s)', None),
1501 '_fdescendants': ('_firstdescendants(%(val)s)', None),
1502 '_matchfiles': ('_matchfiles(%(val)s)', None),
1502 '_matchfiles': ('_matchfiles(%(val)s)', None),
1503 'date': ('date(%(val)r)', None),
1503 'date': ('date(%(val)r)', None),
1504 'branch': ('branch(%(val)r)', ' or '),
1504 'branch': ('branch(%(val)r)', ' or '),
1505 '_patslog': ('filelog(%(val)r)', ' or '),
1505 '_patslog': ('filelog(%(val)r)', ' or '),
1506 '_patsfollow': ('follow(%(val)r)', ' or '),
1506 '_patsfollow': ('follow(%(val)r)', ' or '),
1507 '_patsfollowfirst': ('_followfirst(%(val)r)', ' or '),
1507 '_patsfollowfirst': ('_followfirst(%(val)r)', ' or '),
1508 'keyword': ('keyword(%(val)r)', ' or '),
1508 'keyword': ('keyword(%(val)r)', ' or '),
1509 'prune': ('not (%(val)r or ancestors(%(val)r))', ' and '),
1509 'prune': ('not (%(val)r or ancestors(%(val)r))', ' and '),
1510 'user': ('user(%(val)r)', ' or '),
1510 'user': ('user(%(val)r)', ' or '),
1511 }
1511 }
1512
1512
1513 opts = dict(opts)
1513 opts = dict(opts)
1514 # follow or not follow?
1514 # follow or not follow?
1515 follow = opts.get('follow') or opts.get('follow_first')
1515 follow = opts.get('follow') or opts.get('follow_first')
1516 followfirst = opts.get('follow_first') and 1 or 0
1516 followfirst = opts.get('follow_first') and 1 or 0
1517 # --follow with FILE behaviour depends on revs...
1517 # --follow with FILE behaviour depends on revs...
1518 startrev = revs[0]
1518 startrev = revs[0]
1519 followdescendants = (len(revs) > 1 and revs[0] < revs[1]) and 1 or 0
1519 followdescendants = (len(revs) > 1 and revs[0] < revs[1]) and 1 or 0
1520
1520
1521 # branch and only_branch are really aliases and must be handled at
1521 # branch and only_branch are really aliases and must be handled at
1522 # the same time
1522 # the same time
1523 opts['branch'] = opts.get('branch', []) + opts.get('only_branch', [])
1523 opts['branch'] = opts.get('branch', []) + opts.get('only_branch', [])
1524 opts['branch'] = [repo.lookupbranch(b) for b in opts['branch']]
1524 opts['branch'] = [repo.lookupbranch(b) for b in opts['branch']]
1525 # pats/include/exclude are passed to match.match() directly in
1525 # pats/include/exclude are passed to match.match() directly in
1526 # _matchfiles() revset but walkchangerevs() builds its matcher with
1526 # _matchfiles() revset but walkchangerevs() builds its matcher with
1527 # scmutil.match(). The difference is input pats are globbed on
1527 # scmutil.match(). The difference is input pats are globbed on
1528 # platforms without shell expansion (windows).
1528 # platforms without shell expansion (windows).
1529 pctx = repo[None]
1529 pctx = repo[None]
1530 match, pats = scmutil.matchandpats(pctx, pats, opts)
1530 match, pats = scmutil.matchandpats(pctx, pats, opts)
1531 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1531 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1532 if not slowpath:
1532 if not slowpath:
1533 for f in match.files():
1533 for f in match.files():
1534 if follow and f not in pctx:
1534 if follow and f not in pctx:
1535 raise util.Abort(_('cannot follow file not in parent '
1535 raise util.Abort(_('cannot follow file not in parent '
1536 'revision: "%s"') % f)
1536 'revision: "%s"') % f)
1537 filelog = repo.file(f)
1537 filelog = repo.file(f)
1538 if not filelog:
1538 if not filelog:
1539 # A zero count may be a directory or deleted file, so
1539 # A zero count may be a directory or deleted file, so
1540 # try to find matching entries on the slow path.
1540 # try to find matching entries on the slow path.
1541 if follow:
1541 if follow:
1542 raise util.Abort(
1542 raise util.Abort(
1543 _('cannot follow nonexistent file: "%s"') % f)
1543 _('cannot follow nonexistent file: "%s"') % f)
1544 slowpath = True
1544 slowpath = True
1545
1545
1546 # We decided to fall back to the slowpath because at least one
1546 # We decided to fall back to the slowpath because at least one
1547 # of the paths was not a file. Check to see if at least one of them
1547 # of the paths was not a file. Check to see if at least one of them
1548 # existed in history - in that case, we'll continue down the
1548 # existed in history - in that case, we'll continue down the
1549 # slowpath; otherwise, we can turn off the slowpath
1549 # slowpath; otherwise, we can turn off the slowpath
1550 if slowpath:
1550 if slowpath:
1551 for path in match.files():
1551 for path in match.files():
1552 if path == '.' or path in repo.store:
1552 if path == '.' or path in repo.store:
1553 break
1553 break
1554 else:
1554 else:
1555 slowpath = False
1555 slowpath = False
1556
1556
1557 if slowpath:
1557 if slowpath:
1558 # See walkchangerevs() slow path.
1558 # See walkchangerevs() slow path.
1559 #
1559 #
1560 if follow:
1560 if follow:
1561 raise util.Abort(_('can only follow copies/renames for explicit '
1561 raise util.Abort(_('can only follow copies/renames for explicit '
1562 'filenames'))
1562 'filenames'))
1563 # pats/include/exclude cannot be represented as separate
1563 # pats/include/exclude cannot be represented as separate
1564 # revset expressions as their filtering logic applies at file
1564 # revset expressions as their filtering logic applies at file
1565 # level. For instance "-I a -X a" matches a revision touching
1565 # level. For instance "-I a -X a" matches a revision touching
1566 # "a" and "b" while "file(a) and not file(b)" does
1566 # "a" and "b" while "file(a) and not file(b)" does
1567 # not. Besides, filesets are evaluated against the working
1567 # not. Besides, filesets are evaluated against the working
1568 # directory.
1568 # directory.
1569 matchargs = ['r:', 'd:relpath']
1569 matchargs = ['r:', 'd:relpath']
1570 for p in pats:
1570 for p in pats:
1571 matchargs.append('p:' + p)
1571 matchargs.append('p:' + p)
1572 for p in opts.get('include', []):
1572 for p in opts.get('include', []):
1573 matchargs.append('i:' + p)
1573 matchargs.append('i:' + p)
1574 for p in opts.get('exclude', []):
1574 for p in opts.get('exclude', []):
1575 matchargs.append('x:' + p)
1575 matchargs.append('x:' + p)
1576 matchargs = ','.join(('%r' % p) for p in matchargs)
1576 matchargs = ','.join(('%r' % p) for p in matchargs)
1577 opts['_matchfiles'] = matchargs
1577 opts['_matchfiles'] = matchargs
1578 else:
1578 else:
1579 if follow:
1579 if follow:
1580 fpats = ('_patsfollow', '_patsfollowfirst')
1580 fpats = ('_patsfollow', '_patsfollowfirst')
1581 fnopats = (('_ancestors', '_fancestors'),
1581 fnopats = (('_ancestors', '_fancestors'),
1582 ('_descendants', '_fdescendants'))
1582 ('_descendants', '_fdescendants'))
1583 if pats:
1583 if pats:
1584 # follow() revset interprets its file argument as a
1584 # follow() revset interprets its file argument as a
1585 # manifest entry, so use match.files(), not pats.
1585 # manifest entry, so use match.files(), not pats.
1586 opts[fpats[followfirst]] = list(match.files())
1586 opts[fpats[followfirst]] = list(match.files())
1587 else:
1587 else:
1588 opts[fnopats[followdescendants][followfirst]] = str(startrev)
1588 opts[fnopats[followdescendants][followfirst]] = str(startrev)
1589 else:
1589 else:
1590 opts['_patslog'] = list(pats)
1590 opts['_patslog'] = list(pats)
1591
1591
1592 filematcher = None
1592 filematcher = None
1593 if opts.get('patch') or opts.get('stat'):
1593 if opts.get('patch') or opts.get('stat'):
1594 if follow:
1594 if follow:
1595 filematcher = _makegraphfilematcher(repo, pats, followfirst)
1595 filematcher = _makegraphfilematcher(repo, pats, followfirst)
1596 else:
1596 else:
1597 filematcher = lambda rev: match
1597 filematcher = lambda rev: match
1598
1598
1599 expr = []
1599 expr = []
1600 for op, val in opts.iteritems():
1600 for op, val in opts.iteritems():
1601 if not val:
1601 if not val:
1602 continue
1602 continue
1603 if op not in opt2revset:
1603 if op not in opt2revset:
1604 continue
1604 continue
1605 revop, andor = opt2revset[op]
1605 revop, andor = opt2revset[op]
1606 if '%(val)' not in revop:
1606 if '%(val)' not in revop:
1607 expr.append(revop)
1607 expr.append(revop)
1608 else:
1608 else:
1609 if not isinstance(val, list):
1609 if not isinstance(val, list):
1610 e = revop % {'val': val}
1610 e = revop % {'val': val}
1611 else:
1611 else:
1612 e = '(' + andor.join((revop % {'val': v}) for v in val) + ')'
1612 e = '(' + andor.join((revop % {'val': v}) for v in val) + ')'
1613 expr.append(e)
1613 expr.append(e)
1614
1614
1615 if expr:
1615 if expr:
1616 expr = '(' + ' and '.join(expr) + ')'
1616 expr = '(' + ' and '.join(expr) + ')'
1617 else:
1617 else:
1618 expr = None
1618 expr = None
1619 return expr, filematcher
1619 return expr, filematcher
1620
1620
1621 def getgraphlogrevs(repo, pats, opts):
1621 def getgraphlogrevs(repo, pats, opts):
1622 """Return (revs, expr, filematcher) where revs is an iterable of
1622 """Return (revs, expr, filematcher) where revs is an iterable of
1623 revision numbers, expr is a revset string built from log options
1623 revision numbers, expr is a revset string built from log options
1624 and file patterns or None, and used to filter 'revs'. If --stat or
1624 and file patterns or None, and used to filter 'revs'. If --stat or
1625 --patch are not passed filematcher is None. Otherwise it is a
1625 --patch are not passed filematcher is None. Otherwise it is a
1626 callable taking a revision number and returning a match objects
1626 callable taking a revision number and returning a match objects
1627 filtering the files to be detailed when displaying the revision.
1627 filtering the files to be detailed when displaying the revision.
1628 """
1628 """
1629 if not len(repo):
1629 if not len(repo):
1630 return [], None, None
1630 return [], None, None
1631 limit = loglimit(opts)
1631 limit = loglimit(opts)
1632 # Default --rev value depends on --follow but --follow behaviour
1632 # Default --rev value depends on --follow but --follow behaviour
1633 # depends on revisions resolved from --rev...
1633 # depends on revisions resolved from --rev...
1634 follow = opts.get('follow') or opts.get('follow_first')
1634 follow = opts.get('follow') or opts.get('follow_first')
1635 possiblyunsorted = False # whether revs might need sorting
1635 possiblyunsorted = False # whether revs might need sorting
1636 if opts.get('rev'):
1636 if opts.get('rev'):
1637 revs = scmutil.revrange(repo, opts['rev'])
1637 revs = scmutil.revrange(repo, opts['rev'])
1638 # Don't sort here because _makegraphlogrevset might depend on the
1638 # Don't sort here because _makegraphlogrevset might depend on the
1639 # order of revs
1639 # order of revs
1640 possiblyunsorted = True
1640 possiblyunsorted = True
1641 else:
1641 else:
1642 if follow and len(repo) > 0:
1642 if follow and len(repo) > 0:
1643 revs = repo.revs('reverse(:.)')
1643 revs = repo.revs('reverse(:.)')
1644 else:
1644 else:
1645 revs = revset.baseset(repo.changelog)
1645 revs = revset.baseset(repo.changelog)
1646 revs.reverse()
1646 revs.reverse()
1647 if not revs:
1647 if not revs:
1648 return [], None, None
1648 return [], None, None
1649 revs = revset.baseset(revs)
1649 revs = revset.baseset(revs)
1650 expr, filematcher = _makegraphlogrevset(repo, pats, opts, revs)
1650 expr, filematcher = _makegraphlogrevset(repo, pats, opts, revs)
1651 if possiblyunsorted:
1651 if possiblyunsorted:
1652 revs.sort(reverse=True)
1652 revs.sort(reverse=True)
1653 if expr:
1653 if expr:
1654 # Revset matchers often operate faster on revisions in changelog
1654 # Revset matchers often operate faster on revisions in changelog
1655 # order, because most filters deal with the changelog.
1655 # order, because most filters deal with the changelog.
1656 revs.reverse()
1656 revs.reverse()
1657 matcher = revset.match(repo.ui, expr)
1657 matcher = revset.match(repo.ui, expr)
1658 # Revset matches can reorder revisions. "A or B" typically returns
1658 # Revset matches can reorder revisions. "A or B" typically returns
1659 # returns the revision matching A then the revision matching B. Sort
1659 # returns the revision matching A then the revision matching B. Sort
1660 # again to fix that.
1660 # again to fix that.
1661 revs = matcher(repo, revs)
1661 revs = matcher(repo, revs)
1662 revs.sort(reverse=True)
1662 revs.sort(reverse=True)
1663 if limit is not None:
1663 if limit is not None:
1664 revs = revs[:limit]
1664 revs = revs[:limit]
1665
1665
1666 return revs, expr, filematcher
1666 return revs, expr, filematcher
1667
1667
1668 def displaygraph(ui, dag, displayer, showparents, edgefn, getrenamed=None,
1668 def displaygraph(ui, dag, displayer, showparents, edgefn, getrenamed=None,
1669 filematcher=None):
1669 filematcher=None):
1670 seen, state = [], graphmod.asciistate()
1670 seen, state = [], graphmod.asciistate()
1671 for rev, type, ctx, parents in dag:
1671 for rev, type, ctx, parents in dag:
1672 char = 'o'
1672 char = 'o'
1673 if ctx.node() in showparents:
1673 if ctx.node() in showparents:
1674 char = '@'
1674 char = '@'
1675 elif ctx.obsolete():
1675 elif ctx.obsolete():
1676 char = 'x'
1676 char = 'x'
1677 copies = None
1677 copies = None
1678 if getrenamed and ctx.rev():
1678 if getrenamed and ctx.rev():
1679 copies = []
1679 copies = []
1680 for fn in ctx.files():
1680 for fn in ctx.files():
1681 rename = getrenamed(fn, ctx.rev())
1681 rename = getrenamed(fn, ctx.rev())
1682 if rename:
1682 if rename:
1683 copies.append((fn, rename[0]))
1683 copies.append((fn, rename[0]))
1684 revmatchfn = None
1684 revmatchfn = None
1685 if filematcher is not None:
1685 if filematcher is not None:
1686 revmatchfn = filematcher(ctx.rev())
1686 revmatchfn = filematcher(ctx.rev())
1687 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
1687 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
1688 lines = displayer.hunk.pop(rev).split('\n')
1688 lines = displayer.hunk.pop(rev).split('\n')
1689 if not lines[-1]:
1689 if not lines[-1]:
1690 del lines[-1]
1690 del lines[-1]
1691 displayer.flush(rev)
1691 displayer.flush(rev)
1692 edges = edgefn(type, char, lines, seen, rev, parents)
1692 edges = edgefn(type, char, lines, seen, rev, parents)
1693 for type, char, lines, coldata in edges:
1693 for type, char, lines, coldata in edges:
1694 graphmod.ascii(ui, state, type, char, lines, coldata)
1694 graphmod.ascii(ui, state, type, char, lines, coldata)
1695 displayer.close()
1695 displayer.close()
1696
1696
1697 def graphlog(ui, repo, *pats, **opts):
1697 def graphlog(ui, repo, *pats, **opts):
1698 # Parameters are identical to log command ones
1698 # Parameters are identical to log command ones
1699 revs, expr, filematcher = getgraphlogrevs(repo, pats, opts)
1699 revs, expr, filematcher = getgraphlogrevs(repo, pats, opts)
1700 revdag = graphmod.dagwalker(repo, revs)
1700 revdag = graphmod.dagwalker(repo, revs)
1701
1701
1702 getrenamed = None
1702 getrenamed = None
1703 if opts.get('copies'):
1703 if opts.get('copies'):
1704 endrev = None
1704 endrev = None
1705 if opts.get('rev'):
1705 if opts.get('rev'):
1706 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
1706 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
1707 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
1707 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
1708 displayer = show_changeset(ui, repo, opts, buffered=True)
1708 displayer = show_changeset(ui, repo, opts, buffered=True)
1709 showparents = [ctx.node() for ctx in repo[None].parents()]
1709 showparents = [ctx.node() for ctx in repo[None].parents()]
1710 displaygraph(ui, revdag, displayer, showparents,
1710 displaygraph(ui, revdag, displayer, showparents,
1711 graphmod.asciiedges, getrenamed, filematcher)
1711 graphmod.asciiedges, getrenamed, filematcher)
1712
1712
1713 def checkunsupportedgraphflags(pats, opts):
1713 def checkunsupportedgraphflags(pats, opts):
1714 for op in ["newest_first"]:
1714 for op in ["newest_first"]:
1715 if op in opts and opts[op]:
1715 if op in opts and opts[op]:
1716 raise util.Abort(_("-G/--graph option is incompatible with --%s")
1716 raise util.Abort(_("-G/--graph option is incompatible with --%s")
1717 % op.replace("_", "-"))
1717 % op.replace("_", "-"))
1718
1718
1719 def graphrevs(repo, nodes, opts):
1719 def graphrevs(repo, nodes, opts):
1720 limit = loglimit(opts)
1720 limit = loglimit(opts)
1721 nodes.reverse()
1721 nodes.reverse()
1722 if limit is not None:
1722 if limit is not None:
1723 nodes = nodes[:limit]
1723 nodes = nodes[:limit]
1724 return graphmod.nodes(repo, nodes)
1724 return graphmod.nodes(repo, nodes)
1725
1725
1726 def add(ui, repo, match, dryrun, listsubrepos, prefix, explicitonly):
1726 def add(ui, repo, match, dryrun, listsubrepos, prefix, explicitonly):
1727 join = lambda f: os.path.join(prefix, f)
1727 join = lambda f: os.path.join(prefix, f)
1728 bad = []
1728 bad = []
1729 oldbad = match.bad
1729 oldbad = match.bad
1730 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1730 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1731 names = []
1731 names = []
1732 wctx = repo[None]
1732 wctx = repo[None]
1733 cca = None
1733 cca = None
1734 abort, warn = scmutil.checkportabilityalert(ui)
1734 abort, warn = scmutil.checkportabilityalert(ui)
1735 if abort or warn:
1735 if abort or warn:
1736 cca = scmutil.casecollisionauditor(ui, abort, repo.dirstate)
1736 cca = scmutil.casecollisionauditor(ui, abort, repo.dirstate)
1737 for f in repo.walk(match):
1737 for f in repo.walk(match):
1738 exact = match.exact(f)
1738 exact = match.exact(f)
1739 if exact or not explicitonly and f not in repo.dirstate:
1739 if exact or not explicitonly and f not in repo.dirstate:
1740 if cca:
1740 if cca:
1741 cca(f)
1741 cca(f)
1742 names.append(f)
1742 names.append(f)
1743 if ui.verbose or not exact:
1743 if ui.verbose or not exact:
1744 ui.status(_('adding %s\n') % match.rel(join(f)))
1744 ui.status(_('adding %s\n') % match.rel(join(f)))
1745
1745
1746 for subpath in sorted(wctx.substate):
1746 for subpath in sorted(wctx.substate):
1747 sub = wctx.sub(subpath)
1747 sub = wctx.sub(subpath)
1748 try:
1748 try:
1749 submatch = matchmod.narrowmatcher(subpath, match)
1749 submatch = matchmod.narrowmatcher(subpath, match)
1750 if listsubrepos:
1750 if listsubrepos:
1751 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
1751 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
1752 False))
1752 False))
1753 else:
1753 else:
1754 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
1754 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
1755 True))
1755 True))
1756 except error.LookupError:
1756 except error.LookupError:
1757 ui.status(_("skipping missing subrepository: %s\n")
1757 ui.status(_("skipping missing subrepository: %s\n")
1758 % join(subpath))
1758 % join(subpath))
1759
1759
1760 if not dryrun:
1760 if not dryrun:
1761 rejected = wctx.add(names, prefix)
1761 rejected = wctx.add(names, prefix)
1762 bad.extend(f for f in rejected if f in match.files())
1762 bad.extend(f for f in rejected if f in match.files())
1763 return bad
1763 return bad
1764
1764
1765 def forget(ui, repo, match, prefix, explicitonly):
1765 def forget(ui, repo, match, prefix, explicitonly):
1766 join = lambda f: os.path.join(prefix, f)
1766 join = lambda f: os.path.join(prefix, f)
1767 bad = []
1767 bad = []
1768 oldbad = match.bad
1768 oldbad = match.bad
1769 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1769 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1770 wctx = repo[None]
1770 wctx = repo[None]
1771 forgot = []
1771 forgot = []
1772 s = repo.status(match=match, clean=True)
1772 s = repo.status(match=match, clean=True)
1773 forget = sorted(s[0] + s[1] + s[3] + s[6])
1773 forget = sorted(s[0] + s[1] + s[3] + s[6])
1774 if explicitonly:
1774 if explicitonly:
1775 forget = [f for f in forget if match.exact(f)]
1775 forget = [f for f in forget if match.exact(f)]
1776
1776
1777 for subpath in sorted(wctx.substate):
1777 for subpath in sorted(wctx.substate):
1778 sub = wctx.sub(subpath)
1778 sub = wctx.sub(subpath)
1779 try:
1779 try:
1780 submatch = matchmod.narrowmatcher(subpath, match)
1780 submatch = matchmod.narrowmatcher(subpath, match)
1781 subbad, subforgot = sub.forget(ui, submatch, prefix)
1781 subbad, subforgot = sub.forget(ui, submatch, prefix)
1782 bad.extend([subpath + '/' + f for f in subbad])
1782 bad.extend([subpath + '/' + f for f in subbad])
1783 forgot.extend([subpath + '/' + f for f in subforgot])
1783 forgot.extend([subpath + '/' + f for f in subforgot])
1784 except error.LookupError:
1784 except error.LookupError:
1785 ui.status(_("skipping missing subrepository: %s\n")
1785 ui.status(_("skipping missing subrepository: %s\n")
1786 % join(subpath))
1786 % join(subpath))
1787
1787
1788 if not explicitonly:
1788 if not explicitonly:
1789 for f in match.files():
1789 for f in match.files():
1790 if f not in repo.dirstate and not os.path.isdir(match.rel(join(f))):
1790 if f not in repo.dirstate and not os.path.isdir(match.rel(join(f))):
1791 if f not in forgot:
1791 if f not in forgot:
1792 if os.path.exists(match.rel(join(f))):
1792 if os.path.exists(match.rel(join(f))):
1793 ui.warn(_('not removing %s: '
1793 ui.warn(_('not removing %s: '
1794 'file is already untracked\n')
1794 'file is already untracked\n')
1795 % match.rel(join(f)))
1795 % match.rel(join(f)))
1796 bad.append(f)
1796 bad.append(f)
1797
1797
1798 for f in forget:
1798 for f in forget:
1799 if ui.verbose or not match.exact(f):
1799 if ui.verbose or not match.exact(f):
1800 ui.status(_('removing %s\n') % match.rel(join(f)))
1800 ui.status(_('removing %s\n') % match.rel(join(f)))
1801
1801
1802 rejected = wctx.forget(forget, prefix)
1802 rejected = wctx.forget(forget, prefix)
1803 bad.extend(f for f in rejected if f in match.files())
1803 bad.extend(f for f in rejected if f in match.files())
1804 forgot.extend(forget)
1804 forgot.extend(forget)
1805 return bad, forgot
1805 return bad, forgot
1806
1806
1807 def duplicatecopies(repo, rev, fromrev):
1807 def duplicatecopies(repo, rev, fromrev):
1808 '''reproduce copies from fromrev to rev in the dirstate'''
1808 '''reproduce copies from fromrev to rev in the dirstate'''
1809 for dst, src in copies.pathcopies(repo[fromrev], repo[rev]).iteritems():
1809 for dst, src in copies.pathcopies(repo[fromrev], repo[rev]).iteritems():
1810 # copies.pathcopies returns backward renames, so dst might not
1810 # copies.pathcopies returns backward renames, so dst might not
1811 # actually be in the dirstate
1811 # actually be in the dirstate
1812 if repo.dirstate[dst] in "nma":
1812 if repo.dirstate[dst] in "nma":
1813 repo.dirstate.copy(src, dst)
1813 repo.dirstate.copy(src, dst)
1814
1814
1815 def commit(ui, repo, commitfunc, pats, opts):
1815 def commit(ui, repo, commitfunc, pats, opts):
1816 '''commit the specified files or all outstanding changes'''
1816 '''commit the specified files or all outstanding changes'''
1817 date = opts.get('date')
1817 date = opts.get('date')
1818 if date:
1818 if date:
1819 opts['date'] = util.parsedate(date)
1819 opts['date'] = util.parsedate(date)
1820 message = logmessage(ui, opts)
1820 message = logmessage(ui, opts)
1821
1821
1822 # extract addremove carefully -- this function can be called from a command
1822 # extract addremove carefully -- this function can be called from a command
1823 # that doesn't support addremove
1823 # that doesn't support addremove
1824 if opts.get('addremove'):
1824 if opts.get('addremove'):
1825 scmutil.addremove(repo, pats, opts)
1825 scmutil.addremove(repo, pats, opts)
1826
1826
1827 return commitfunc(ui, repo, message,
1827 return commitfunc(ui, repo, message,
1828 scmutil.match(repo[None], pats, opts), opts)
1828 scmutil.match(repo[None], pats, opts), opts)
1829
1829
1830 def amend(ui, repo, commitfunc, old, extra, pats, opts):
1830 def amend(ui, repo, commitfunc, old, extra, pats, opts):
1831 ui.note(_('amending changeset %s\n') % old)
1831 ui.note(_('amending changeset %s\n') % old)
1832 base = old.p1()
1832 base = old.p1()
1833
1833
1834 wlock = lock = newid = None
1834 wlock = lock = newid = None
1835 try:
1835 try:
1836 wlock = repo.wlock()
1836 wlock = repo.wlock()
1837 lock = repo.lock()
1837 lock = repo.lock()
1838 tr = repo.transaction('amend')
1838 tr = repo.transaction('amend')
1839 try:
1839 try:
1840 # See if we got a message from -m or -l, if not, open the editor
1840 # See if we got a message from -m or -l, if not, open the editor
1841 # with the message of the changeset to amend
1841 # with the message of the changeset to amend
1842 message = logmessage(ui, opts)
1842 message = logmessage(ui, opts)
1843 # ensure logfile does not conflict with later enforcement of the
1843 # ensure logfile does not conflict with later enforcement of the
1844 # message. potential logfile content has been processed by
1844 # message. potential logfile content has been processed by
1845 # `logmessage` anyway.
1845 # `logmessage` anyway.
1846 opts.pop('logfile')
1846 opts.pop('logfile')
1847 # First, do a regular commit to record all changes in the working
1847 # First, do a regular commit to record all changes in the working
1848 # directory (if there are any)
1848 # directory (if there are any)
1849 ui.callhooks = False
1849 ui.callhooks = False
1850 currentbookmark = repo._bookmarkcurrent
1850 currentbookmark = repo._bookmarkcurrent
1851 try:
1851 try:
1852 repo._bookmarkcurrent = None
1852 repo._bookmarkcurrent = None
1853 opts['message'] = 'temporary amend commit for %s' % old
1853 opts['message'] = 'temporary amend commit for %s' % old
1854 node = commit(ui, repo, commitfunc, pats, opts)
1854 node = commit(ui, repo, commitfunc, pats, opts)
1855 finally:
1855 finally:
1856 repo._bookmarkcurrent = currentbookmark
1856 repo._bookmarkcurrent = currentbookmark
1857 ui.callhooks = True
1857 ui.callhooks = True
1858 ctx = repo[node]
1858 ctx = repo[node]
1859
1859
1860 # Participating changesets:
1860 # Participating changesets:
1861 #
1861 #
1862 # node/ctx o - new (intermediate) commit that contains changes
1862 # node/ctx o - new (intermediate) commit that contains changes
1863 # | from working dir to go into amending commit
1863 # | from working dir to go into amending commit
1864 # | (or a workingctx if there were no changes)
1864 # | (or a workingctx if there were no changes)
1865 # |
1865 # |
1866 # old o - changeset to amend
1866 # old o - changeset to amend
1867 # |
1867 # |
1868 # base o - parent of amending changeset
1868 # base o - parent of amending changeset
1869
1869
1870 # Update extra dict from amended commit (e.g. to preserve graft
1870 # Update extra dict from amended commit (e.g. to preserve graft
1871 # source)
1871 # source)
1872 extra.update(old.extra())
1872 extra.update(old.extra())
1873
1873
1874 # Also update it from the intermediate commit or from the wctx
1874 # Also update it from the intermediate commit or from the wctx
1875 extra.update(ctx.extra())
1875 extra.update(ctx.extra())
1876
1876
1877 if len(old.parents()) > 1:
1877 if len(old.parents()) > 1:
1878 # ctx.files() isn't reliable for merges, so fall back to the
1878 # ctx.files() isn't reliable for merges, so fall back to the
1879 # slower repo.status() method
1879 # slower repo.status() method
1880 files = set([fn for st in repo.status(base, old)[:3]
1880 files = set([fn for st in repo.status(base, old)[:3]
1881 for fn in st])
1881 for fn in st])
1882 else:
1882 else:
1883 files = set(old.files())
1883 files = set(old.files())
1884
1884
1885 # Second, we use either the commit we just did, or if there were no
1885 # Second, we use either the commit we just did, or if there were no
1886 # changes the parent of the working directory as the version of the
1886 # changes the parent of the working directory as the version of the
1887 # files in the final amend commit
1887 # files in the final amend commit
1888 if node:
1888 if node:
1889 ui.note(_('copying changeset %s to %s\n') % (ctx, base))
1889 ui.note(_('copying changeset %s to %s\n') % (ctx, base))
1890
1890
1891 user = ctx.user()
1891 user = ctx.user()
1892 date = ctx.date()
1892 date = ctx.date()
1893 # Recompute copies (avoid recording a -> b -> a)
1893 # Recompute copies (avoid recording a -> b -> a)
1894 copied = copies.pathcopies(base, ctx)
1894 copied = copies.pathcopies(base, ctx)
1895
1895
1896 # Prune files which were reverted by the updates: if old
1896 # Prune files which were reverted by the updates: if old
1897 # introduced file X and our intermediate commit, node,
1897 # introduced file X and our intermediate commit, node,
1898 # renamed that file, then those two files are the same and
1898 # renamed that file, then those two files are the same and
1899 # we can discard X from our list of files. Likewise if X
1899 # we can discard X from our list of files. Likewise if X
1900 # was deleted, it's no longer relevant
1900 # was deleted, it's no longer relevant
1901 files.update(ctx.files())
1901 files.update(ctx.files())
1902
1902
1903 def samefile(f):
1903 def samefile(f):
1904 if f in ctx.manifest():
1904 if f in ctx.manifest():
1905 a = ctx.filectx(f)
1905 a = ctx.filectx(f)
1906 if f in base.manifest():
1906 if f in base.manifest():
1907 b = base.filectx(f)
1907 b = base.filectx(f)
1908 return (not a.cmp(b)
1908 return (not a.cmp(b)
1909 and a.flags() == b.flags())
1909 and a.flags() == b.flags())
1910 else:
1910 else:
1911 return False
1911 return False
1912 else:
1912 else:
1913 return f not in base.manifest()
1913 return f not in base.manifest()
1914 files = [f for f in files if not samefile(f)]
1914 files = [f for f in files if not samefile(f)]
1915
1915
1916 def filectxfn(repo, ctx_, path):
1916 def filectxfn(repo, ctx_, path):
1917 try:
1917 try:
1918 fctx = ctx[path]
1918 fctx = ctx[path]
1919 flags = fctx.flags()
1919 flags = fctx.flags()
1920 mctx = context.memfilectx(fctx.path(), fctx.data(),
1920 mctx = context.memfilectx(fctx.path(), fctx.data(),
1921 islink='l' in flags,
1921 islink='l' in flags,
1922 isexec='x' in flags,
1922 isexec='x' in flags,
1923 copied=copied.get(path))
1923 copied=copied.get(path))
1924 return mctx
1924 return mctx
1925 except KeyError:
1925 except KeyError:
1926 raise IOError
1926 raise IOError
1927 else:
1927 else:
1928 ui.note(_('copying changeset %s to %s\n') % (old, base))
1928 ui.note(_('copying changeset %s to %s\n') % (old, base))
1929
1929
1930 # Use version of files as in the old cset
1930 # Use version of files as in the old cset
1931 def filectxfn(repo, ctx_, path):
1931 def filectxfn(repo, ctx_, path):
1932 try:
1932 try:
1933 return old.filectx(path)
1933 return old.filectx(path)
1934 except KeyError:
1934 except KeyError:
1935 raise IOError
1935 raise IOError
1936
1936
1937 user = opts.get('user') or old.user()
1937 user = opts.get('user') or old.user()
1938 date = opts.get('date') or old.date()
1938 date = opts.get('date') or old.date()
1939 editmsg = False
1939 editmsg = False
1940 if not message:
1940 if not message:
1941 editmsg = True
1941 editmsg = True
1942 message = old.description()
1942 message = old.description()
1943
1943
1944 pureextra = extra.copy()
1944 pureextra = extra.copy()
1945 extra['amend_source'] = old.hex()
1945 extra['amend_source'] = old.hex()
1946
1946
1947 new = context.memctx(repo,
1947 new = context.memctx(repo,
1948 parents=[base.node(), old.p2().node()],
1948 parents=[base.node(), old.p2().node()],
1949 text=message,
1949 text=message,
1950 files=files,
1950 files=files,
1951 filectxfn=filectxfn,
1951 filectxfn=filectxfn,
1952 user=user,
1952 user=user,
1953 date=date,
1953 date=date,
1954 extra=extra)
1954 extra=extra)
1955 if editmsg:
1955 if editmsg:
1956 new._text = commitforceeditor(repo, new, [])
1956 new._text = commitforceeditor(repo, new, [])
1957
1957
1958 newdesc = changelog.stripdesc(new.description())
1958 newdesc = changelog.stripdesc(new.description())
1959 if ((not node)
1959 if ((not node)
1960 and newdesc == old.description()
1960 and newdesc == old.description()
1961 and user == old.user()
1961 and user == old.user()
1962 and date == old.date()
1962 and date == old.date()
1963 and pureextra == old.extra()):
1963 and pureextra == old.extra()):
1964 # nothing changed. continuing here would create a new node
1964 # nothing changed. continuing here would create a new node
1965 # anyway because of the amend_source noise.
1965 # anyway because of the amend_source noise.
1966 #
1966 #
1967 # This not what we expect from amend.
1967 # This not what we expect from amend.
1968 return old.node()
1968 return old.node()
1969
1969
1970 ph = repo.ui.config('phases', 'new-commit', phases.draft)
1970 ph = repo.ui.config('phases', 'new-commit', phases.draft)
1971 try:
1971 try:
1972 repo.ui.setconfig('phases', 'new-commit', old.phase())
1972 if opts.get('secret'):
1973 commitphase = 'secret'
1974 else:
1975 commitphase = old.phase()
1976 repo.ui.setconfig('phases', 'new-commit', commitphase)
1973 newid = repo.commitctx(new)
1977 newid = repo.commitctx(new)
1974 finally:
1978 finally:
1975 repo.ui.setconfig('phases', 'new-commit', ph)
1979 repo.ui.setconfig('phases', 'new-commit', ph)
1976 if newid != old.node():
1980 if newid != old.node():
1977 # Reroute the working copy parent to the new changeset
1981 # Reroute the working copy parent to the new changeset
1978 repo.setparents(newid, nullid)
1982 repo.setparents(newid, nullid)
1979
1983
1980 # Move bookmarks from old parent to amend commit
1984 # Move bookmarks from old parent to amend commit
1981 bms = repo.nodebookmarks(old.node())
1985 bms = repo.nodebookmarks(old.node())
1982 if bms:
1986 if bms:
1983 marks = repo._bookmarks
1987 marks = repo._bookmarks
1984 for bm in bms:
1988 for bm in bms:
1985 marks[bm] = newid
1989 marks[bm] = newid
1986 marks.write()
1990 marks.write()
1987 #commit the whole amend process
1991 #commit the whole amend process
1988 if obsolete._enabled and newid != old.node():
1992 if obsolete._enabled and newid != old.node():
1989 # mark the new changeset as successor of the rewritten one
1993 # mark the new changeset as successor of the rewritten one
1990 new = repo[newid]
1994 new = repo[newid]
1991 obs = [(old, (new,))]
1995 obs = [(old, (new,))]
1992 if node:
1996 if node:
1993 obs.append((ctx, ()))
1997 obs.append((ctx, ()))
1994
1998
1995 obsolete.createmarkers(repo, obs)
1999 obsolete.createmarkers(repo, obs)
1996 tr.close()
2000 tr.close()
1997 finally:
2001 finally:
1998 tr.release()
2002 tr.release()
1999 if (not obsolete._enabled) and newid != old.node():
2003 if (not obsolete._enabled) and newid != old.node():
2000 # Strip the intermediate commit (if there was one) and the amended
2004 # Strip the intermediate commit (if there was one) and the amended
2001 # commit
2005 # commit
2002 if node:
2006 if node:
2003 ui.note(_('stripping intermediate changeset %s\n') % ctx)
2007 ui.note(_('stripping intermediate changeset %s\n') % ctx)
2004 ui.note(_('stripping amended changeset %s\n') % old)
2008 ui.note(_('stripping amended changeset %s\n') % old)
2005 repair.strip(ui, repo, old.node(), topic='amend-backup')
2009 repair.strip(ui, repo, old.node(), topic='amend-backup')
2006 finally:
2010 finally:
2007 if newid is None:
2011 if newid is None:
2008 repo.dirstate.invalidate()
2012 repo.dirstate.invalidate()
2009 lockmod.release(lock, wlock)
2013 lockmod.release(lock, wlock)
2010 return newid
2014 return newid
2011
2015
2012 def commiteditor(repo, ctx, subs):
2016 def commiteditor(repo, ctx, subs):
2013 if ctx.description():
2017 if ctx.description():
2014 return ctx.description()
2018 return ctx.description()
2015 return commitforceeditor(repo, ctx, subs)
2019 return commitforceeditor(repo, ctx, subs)
2016
2020
2017 def commitforceeditor(repo, ctx, subs):
2021 def commitforceeditor(repo, ctx, subs):
2018 edittext = []
2022 edittext = []
2019 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
2023 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
2020 if ctx.description():
2024 if ctx.description():
2021 edittext.append(ctx.description())
2025 edittext.append(ctx.description())
2022 edittext.append("")
2026 edittext.append("")
2023 edittext.append("") # Empty line between message and comments.
2027 edittext.append("") # Empty line between message and comments.
2024 edittext.append(_("HG: Enter commit message."
2028 edittext.append(_("HG: Enter commit message."
2025 " Lines beginning with 'HG:' are removed."))
2029 " Lines beginning with 'HG:' are removed."))
2026 edittext.append(_("HG: Leave message empty to abort commit."))
2030 edittext.append(_("HG: Leave message empty to abort commit."))
2027 edittext.append("HG: --")
2031 edittext.append("HG: --")
2028 edittext.append(_("HG: user: %s") % ctx.user())
2032 edittext.append(_("HG: user: %s") % ctx.user())
2029 if ctx.p2():
2033 if ctx.p2():
2030 edittext.append(_("HG: branch merge"))
2034 edittext.append(_("HG: branch merge"))
2031 if ctx.branch():
2035 if ctx.branch():
2032 edittext.append(_("HG: branch '%s'") % ctx.branch())
2036 edittext.append(_("HG: branch '%s'") % ctx.branch())
2033 if bookmarks.iscurrent(repo):
2037 if bookmarks.iscurrent(repo):
2034 edittext.append(_("HG: bookmark '%s'") % repo._bookmarkcurrent)
2038 edittext.append(_("HG: bookmark '%s'") % repo._bookmarkcurrent)
2035 edittext.extend([_("HG: subrepo %s") % s for s in subs])
2039 edittext.extend([_("HG: subrepo %s") % s for s in subs])
2036 edittext.extend([_("HG: added %s") % f for f in added])
2040 edittext.extend([_("HG: added %s") % f for f in added])
2037 edittext.extend([_("HG: changed %s") % f for f in modified])
2041 edittext.extend([_("HG: changed %s") % f for f in modified])
2038 edittext.extend([_("HG: removed %s") % f for f in removed])
2042 edittext.extend([_("HG: removed %s") % f for f in removed])
2039 if not added and not modified and not removed:
2043 if not added and not modified and not removed:
2040 edittext.append(_("HG: no files changed"))
2044 edittext.append(_("HG: no files changed"))
2041 edittext.append("")
2045 edittext.append("")
2042 # run editor in the repository root
2046 # run editor in the repository root
2043 olddir = os.getcwd()
2047 olddir = os.getcwd()
2044 os.chdir(repo.root)
2048 os.chdir(repo.root)
2045 text = repo.ui.edit("\n".join(edittext), ctx.user(), ctx.extra())
2049 text = repo.ui.edit("\n".join(edittext), ctx.user(), ctx.extra())
2046 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
2050 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
2047 os.chdir(olddir)
2051 os.chdir(olddir)
2048
2052
2049 if not text.strip():
2053 if not text.strip():
2050 raise util.Abort(_("empty commit message"))
2054 raise util.Abort(_("empty commit message"))
2051
2055
2052 return text
2056 return text
2053
2057
2054 def commitstatus(repo, node, branch, bheads=None, opts={}):
2058 def commitstatus(repo, node, branch, bheads=None, opts={}):
2055 ctx = repo[node]
2059 ctx = repo[node]
2056 parents = ctx.parents()
2060 parents = ctx.parents()
2057
2061
2058 if (not opts.get('amend') and bheads and node not in bheads and not
2062 if (not opts.get('amend') and bheads and node not in bheads and not
2059 [x for x in parents if x.node() in bheads and x.branch() == branch]):
2063 [x for x in parents if x.node() in bheads and x.branch() == branch]):
2060 repo.ui.status(_('created new head\n'))
2064 repo.ui.status(_('created new head\n'))
2061 # The message is not printed for initial roots. For the other
2065 # The message is not printed for initial roots. For the other
2062 # changesets, it is printed in the following situations:
2066 # changesets, it is printed in the following situations:
2063 #
2067 #
2064 # Par column: for the 2 parents with ...
2068 # Par column: for the 2 parents with ...
2065 # N: null or no parent
2069 # N: null or no parent
2066 # B: parent is on another named branch
2070 # B: parent is on another named branch
2067 # C: parent is a regular non head changeset
2071 # C: parent is a regular non head changeset
2068 # H: parent was a branch head of the current branch
2072 # H: parent was a branch head of the current branch
2069 # Msg column: whether we print "created new head" message
2073 # Msg column: whether we print "created new head" message
2070 # In the following, it is assumed that there already exists some
2074 # In the following, it is assumed that there already exists some
2071 # initial branch heads of the current branch, otherwise nothing is
2075 # initial branch heads of the current branch, otherwise nothing is
2072 # printed anyway.
2076 # printed anyway.
2073 #
2077 #
2074 # Par Msg Comment
2078 # Par Msg Comment
2075 # N N y additional topo root
2079 # N N y additional topo root
2076 #
2080 #
2077 # B N y additional branch root
2081 # B N y additional branch root
2078 # C N y additional topo head
2082 # C N y additional topo head
2079 # H N n usual case
2083 # H N n usual case
2080 #
2084 #
2081 # B B y weird additional branch root
2085 # B B y weird additional branch root
2082 # C B y branch merge
2086 # C B y branch merge
2083 # H B n merge with named branch
2087 # H B n merge with named branch
2084 #
2088 #
2085 # C C y additional head from merge
2089 # C C y additional head from merge
2086 # C H n merge with a head
2090 # C H n merge with a head
2087 #
2091 #
2088 # H H n head merge: head count decreases
2092 # H H n head merge: head count decreases
2089
2093
2090 if not opts.get('close_branch'):
2094 if not opts.get('close_branch'):
2091 for r in parents:
2095 for r in parents:
2092 if r.closesbranch() and r.branch() == branch:
2096 if r.closesbranch() and r.branch() == branch:
2093 repo.ui.status(_('reopening closed branch head %d\n') % r)
2097 repo.ui.status(_('reopening closed branch head %d\n') % r)
2094
2098
2095 if repo.ui.debugflag:
2099 if repo.ui.debugflag:
2096 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
2100 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
2097 elif repo.ui.verbose:
2101 elif repo.ui.verbose:
2098 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
2102 repo.ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
2099
2103
2100 def revert(ui, repo, ctx, parents, *pats, **opts):
2104 def revert(ui, repo, ctx, parents, *pats, **opts):
2101 parent, p2 = parents
2105 parent, p2 = parents
2102 node = ctx.node()
2106 node = ctx.node()
2103
2107
2104 mf = ctx.manifest()
2108 mf = ctx.manifest()
2105 if node == parent:
2109 if node == parent:
2106 pmf = mf
2110 pmf = mf
2107 else:
2111 else:
2108 pmf = None
2112 pmf = None
2109
2113
2110 # need all matching names in dirstate and manifest of target rev,
2114 # need all matching names in dirstate and manifest of target rev,
2111 # so have to walk both. do not print errors if files exist in one
2115 # so have to walk both. do not print errors if files exist in one
2112 # but not other.
2116 # but not other.
2113
2117
2114 names = {}
2118 names = {}
2115
2119
2116 wlock = repo.wlock()
2120 wlock = repo.wlock()
2117 try:
2121 try:
2118 # walk dirstate.
2122 # walk dirstate.
2119
2123
2120 m = scmutil.match(repo[None], pats, opts)
2124 m = scmutil.match(repo[None], pats, opts)
2121 m.bad = lambda x, y: False
2125 m.bad = lambda x, y: False
2122 for abs in repo.walk(m):
2126 for abs in repo.walk(m):
2123 names[abs] = m.rel(abs), m.exact(abs)
2127 names[abs] = m.rel(abs), m.exact(abs)
2124
2128
2125 # walk target manifest.
2129 # walk target manifest.
2126
2130
2127 def badfn(path, msg):
2131 def badfn(path, msg):
2128 if path in names:
2132 if path in names:
2129 return
2133 return
2130 if path in ctx.substate:
2134 if path in ctx.substate:
2131 return
2135 return
2132 path_ = path + '/'
2136 path_ = path + '/'
2133 for f in names:
2137 for f in names:
2134 if f.startswith(path_):
2138 if f.startswith(path_):
2135 return
2139 return
2136 ui.warn("%s: %s\n" % (m.rel(path), msg))
2140 ui.warn("%s: %s\n" % (m.rel(path), msg))
2137
2141
2138 m = scmutil.match(ctx, pats, opts)
2142 m = scmutil.match(ctx, pats, opts)
2139 m.bad = badfn
2143 m.bad = badfn
2140 for abs in ctx.walk(m):
2144 for abs in ctx.walk(m):
2141 if abs not in names:
2145 if abs not in names:
2142 names[abs] = m.rel(abs), m.exact(abs)
2146 names[abs] = m.rel(abs), m.exact(abs)
2143
2147
2144 # get the list of subrepos that must be reverted
2148 # get the list of subrepos that must be reverted
2145 targetsubs = sorted(s for s in ctx.substate if m(s))
2149 targetsubs = sorted(s for s in ctx.substate if m(s))
2146 m = scmutil.matchfiles(repo, names)
2150 m = scmutil.matchfiles(repo, names)
2147 changes = repo.status(match=m)[:4]
2151 changes = repo.status(match=m)[:4]
2148 modified, added, removed, deleted = map(set, changes)
2152 modified, added, removed, deleted = map(set, changes)
2149
2153
2150 # if f is a rename, also revert the source
2154 # if f is a rename, also revert the source
2151 cwd = repo.getcwd()
2155 cwd = repo.getcwd()
2152 for f in added:
2156 for f in added:
2153 src = repo.dirstate.copied(f)
2157 src = repo.dirstate.copied(f)
2154 if src and src not in names and repo.dirstate[src] == 'r':
2158 if src and src not in names and repo.dirstate[src] == 'r':
2155 removed.add(src)
2159 removed.add(src)
2156 names[src] = (repo.pathto(src, cwd), True)
2160 names[src] = (repo.pathto(src, cwd), True)
2157
2161
2158 def removeforget(abs):
2162 def removeforget(abs):
2159 if repo.dirstate[abs] == 'a':
2163 if repo.dirstate[abs] == 'a':
2160 return _('forgetting %s\n')
2164 return _('forgetting %s\n')
2161 return _('removing %s\n')
2165 return _('removing %s\n')
2162
2166
2163 revert = ([], _('reverting %s\n'))
2167 revert = ([], _('reverting %s\n'))
2164 add = ([], _('adding %s\n'))
2168 add = ([], _('adding %s\n'))
2165 remove = ([], removeforget)
2169 remove = ([], removeforget)
2166 undelete = ([], _('undeleting %s\n'))
2170 undelete = ([], _('undeleting %s\n'))
2167
2171
2168 disptable = (
2172 disptable = (
2169 # dispatch table:
2173 # dispatch table:
2170 # file state
2174 # file state
2171 # action if in target manifest
2175 # action if in target manifest
2172 # action if not in target manifest
2176 # action if not in target manifest
2173 # make backup if in target manifest
2177 # make backup if in target manifest
2174 # make backup if not in target manifest
2178 # make backup if not in target manifest
2175 (modified, revert, remove, True, True),
2179 (modified, revert, remove, True, True),
2176 (added, revert, remove, True, False),
2180 (added, revert, remove, True, False),
2177 (removed, undelete, None, True, False),
2181 (removed, undelete, None, True, False),
2178 (deleted, revert, remove, False, False),
2182 (deleted, revert, remove, False, False),
2179 )
2183 )
2180
2184
2181 for abs, (rel, exact) in sorted(names.items()):
2185 for abs, (rel, exact) in sorted(names.items()):
2182 mfentry = mf.get(abs)
2186 mfentry = mf.get(abs)
2183 target = repo.wjoin(abs)
2187 target = repo.wjoin(abs)
2184 def handle(xlist, dobackup):
2188 def handle(xlist, dobackup):
2185 xlist[0].append(abs)
2189 xlist[0].append(abs)
2186 if (dobackup and not opts.get('no_backup') and
2190 if (dobackup and not opts.get('no_backup') and
2187 os.path.lexists(target) and
2191 os.path.lexists(target) and
2188 abs in ctx and repo[None][abs].cmp(ctx[abs])):
2192 abs in ctx and repo[None][abs].cmp(ctx[abs])):
2189 bakname = "%s.orig" % rel
2193 bakname = "%s.orig" % rel
2190 ui.note(_('saving current version of %s as %s\n') %
2194 ui.note(_('saving current version of %s as %s\n') %
2191 (rel, bakname))
2195 (rel, bakname))
2192 if not opts.get('dry_run'):
2196 if not opts.get('dry_run'):
2193 util.rename(target, bakname)
2197 util.rename(target, bakname)
2194 if ui.verbose or not exact:
2198 if ui.verbose or not exact:
2195 msg = xlist[1]
2199 msg = xlist[1]
2196 if not isinstance(msg, basestring):
2200 if not isinstance(msg, basestring):
2197 msg = msg(abs)
2201 msg = msg(abs)
2198 ui.status(msg % rel)
2202 ui.status(msg % rel)
2199 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2203 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2200 if abs not in table:
2204 if abs not in table:
2201 continue
2205 continue
2202 # file has changed in dirstate
2206 # file has changed in dirstate
2203 if mfentry:
2207 if mfentry:
2204 handle(hitlist, backuphit)
2208 handle(hitlist, backuphit)
2205 elif misslist is not None:
2209 elif misslist is not None:
2206 handle(misslist, backupmiss)
2210 handle(misslist, backupmiss)
2207 break
2211 break
2208 else:
2212 else:
2209 if abs not in repo.dirstate:
2213 if abs not in repo.dirstate:
2210 if mfentry:
2214 if mfentry:
2211 handle(add, True)
2215 handle(add, True)
2212 elif exact:
2216 elif exact:
2213 ui.warn(_('file not managed: %s\n') % rel)
2217 ui.warn(_('file not managed: %s\n') % rel)
2214 continue
2218 continue
2215 # file has not changed in dirstate
2219 # file has not changed in dirstate
2216 if node == parent:
2220 if node == parent:
2217 if exact:
2221 if exact:
2218 ui.warn(_('no changes needed to %s\n') % rel)
2222 ui.warn(_('no changes needed to %s\n') % rel)
2219 continue
2223 continue
2220 if pmf is None:
2224 if pmf is None:
2221 # only need parent manifest in this unlikely case,
2225 # only need parent manifest in this unlikely case,
2222 # so do not read by default
2226 # so do not read by default
2223 pmf = repo[parent].manifest()
2227 pmf = repo[parent].manifest()
2224 if abs in pmf and mfentry:
2228 if abs in pmf and mfentry:
2225 # if version of file is same in parent and target
2229 # if version of file is same in parent and target
2226 # manifests, do nothing
2230 # manifests, do nothing
2227 if (pmf[abs] != mfentry or
2231 if (pmf[abs] != mfentry or
2228 pmf.flags(abs) != mf.flags(abs)):
2232 pmf.flags(abs) != mf.flags(abs)):
2229 handle(revert, False)
2233 handle(revert, False)
2230 else:
2234 else:
2231 handle(remove, False)
2235 handle(remove, False)
2232 if not opts.get('dry_run'):
2236 if not opts.get('dry_run'):
2233 _performrevert(repo, parents, ctx, revert, add, remove, undelete)
2237 _performrevert(repo, parents, ctx, revert, add, remove, undelete)
2234
2238
2235 if targetsubs:
2239 if targetsubs:
2236 # Revert the subrepos on the revert list
2240 # Revert the subrepos on the revert list
2237 for sub in targetsubs:
2241 for sub in targetsubs:
2238 ctx.sub(sub).revert(ui, ctx.substate[sub], *pats, **opts)
2242 ctx.sub(sub).revert(ui, ctx.substate[sub], *pats, **opts)
2239 finally:
2243 finally:
2240 wlock.release()
2244 wlock.release()
2241
2245
2242 def _performrevert(repo, parents, ctx, revert, add, remove, undelete):
2246 def _performrevert(repo, parents, ctx, revert, add, remove, undelete):
2243 """function that actually perform all the action computed for revert
2247 """function that actually perform all the action computed for revert
2244
2248
2245 This is an independent function to let extension to plug in and react to
2249 This is an independent function to let extension to plug in and react to
2246 the imminent revert.
2250 the imminent revert.
2247
2251
2248 Make sure you have the working directory locked when caling this function.
2252 Make sure you have the working directory locked when caling this function.
2249 """
2253 """
2250 parent, p2 = parents
2254 parent, p2 = parents
2251 node = ctx.node()
2255 node = ctx.node()
2252 def checkout(f):
2256 def checkout(f):
2253 fc = ctx[f]
2257 fc = ctx[f]
2254 repo.wwrite(f, fc.data(), fc.flags())
2258 repo.wwrite(f, fc.data(), fc.flags())
2255
2259
2256 audit_path = pathutil.pathauditor(repo.root)
2260 audit_path = pathutil.pathauditor(repo.root)
2257 for f in remove[0]:
2261 for f in remove[0]:
2258 if repo.dirstate[f] == 'a':
2262 if repo.dirstate[f] == 'a':
2259 repo.dirstate.drop(f)
2263 repo.dirstate.drop(f)
2260 continue
2264 continue
2261 audit_path(f)
2265 audit_path(f)
2262 try:
2266 try:
2263 util.unlinkpath(repo.wjoin(f))
2267 util.unlinkpath(repo.wjoin(f))
2264 except OSError:
2268 except OSError:
2265 pass
2269 pass
2266 repo.dirstate.remove(f)
2270 repo.dirstate.remove(f)
2267
2271
2268 normal = None
2272 normal = None
2269 if node == parent:
2273 if node == parent:
2270 # We're reverting to our parent. If possible, we'd like status
2274 # We're reverting to our parent. If possible, we'd like status
2271 # to report the file as clean. We have to use normallookup for
2275 # to report the file as clean. We have to use normallookup for
2272 # merges to avoid losing information about merged/dirty files.
2276 # merges to avoid losing information about merged/dirty files.
2273 if p2 != nullid:
2277 if p2 != nullid:
2274 normal = repo.dirstate.normallookup
2278 normal = repo.dirstate.normallookup
2275 else:
2279 else:
2276 normal = repo.dirstate.normal
2280 normal = repo.dirstate.normal
2277 for f in revert[0]:
2281 for f in revert[0]:
2278 checkout(f)
2282 checkout(f)
2279 if normal:
2283 if normal:
2280 normal(f)
2284 normal(f)
2281
2285
2282 for f in add[0]:
2286 for f in add[0]:
2283 checkout(f)
2287 checkout(f)
2284 repo.dirstate.add(f)
2288 repo.dirstate.add(f)
2285
2289
2286 normal = repo.dirstate.normallookup
2290 normal = repo.dirstate.normallookup
2287 if node == parent and p2 == nullid:
2291 if node == parent and p2 == nullid:
2288 normal = repo.dirstate.normal
2292 normal = repo.dirstate.normal
2289 for f in undelete[0]:
2293 for f in undelete[0]:
2290 checkout(f)
2294 checkout(f)
2291 normal(f)
2295 normal(f)
2292
2296
2293 copied = copies.pathcopies(repo[parent], ctx)
2297 copied = copies.pathcopies(repo[parent], ctx)
2294
2298
2295 for f in add[0] + undelete[0] + revert[0]:
2299 for f in add[0] + undelete[0] + revert[0]:
2296 if f in copied:
2300 if f in copied:
2297 repo.dirstate.copy(copied[f], f)
2301 repo.dirstate.copy(copied[f], f)
2298
2302
2299 def command(table):
2303 def command(table):
2300 '''returns a function object bound to table which can be used as
2304 '''returns a function object bound to table which can be used as
2301 a decorator for populating table as a command table'''
2305 a decorator for populating table as a command table'''
2302
2306
2303 def cmd(name, options=(), synopsis=None):
2307 def cmd(name, options=(), synopsis=None):
2304 def decorator(func):
2308 def decorator(func):
2305 if synopsis:
2309 if synopsis:
2306 table[name] = func, list(options), synopsis
2310 table[name] = func, list(options), synopsis
2307 else:
2311 else:
2308 table[name] = func, list(options)
2312 table[name] = func, list(options)
2309 return func
2313 return func
2310 return decorator
2314 return decorator
2311
2315
2312 return cmd
2316 return cmd
2313
2317
2314 # a list of (ui, repo) functions called by commands.summary
2318 # a list of (ui, repo) functions called by commands.summary
2315 summaryhooks = util.hooks()
2319 summaryhooks = util.hooks()
2316
2320
2317 # A list of state files kept by multistep operations like graft.
2321 # A list of state files kept by multistep operations like graft.
2318 # Since graft cannot be aborted, it is considered 'clearable' by update.
2322 # Since graft cannot be aborted, it is considered 'clearable' by update.
2319 # note: bisect is intentionally excluded
2323 # note: bisect is intentionally excluded
2320 # (state file, clearable, allowcommit, error, hint)
2324 # (state file, clearable, allowcommit, error, hint)
2321 unfinishedstates = [
2325 unfinishedstates = [
2322 ('graftstate', True, False, _('graft in progress'),
2326 ('graftstate', True, False, _('graft in progress'),
2323 _("use 'hg graft --continue' or 'hg update' to abort")),
2327 _("use 'hg graft --continue' or 'hg update' to abort")),
2324 ('updatestate', True, False, _('last update was interrupted'),
2328 ('updatestate', True, False, _('last update was interrupted'),
2325 _("use 'hg update' to get a consistent checkout"))
2329 _("use 'hg update' to get a consistent checkout"))
2326 ]
2330 ]
2327
2331
2328 def checkunfinished(repo, commit=False):
2332 def checkunfinished(repo, commit=False):
2329 '''Look for an unfinished multistep operation, like graft, and abort
2333 '''Look for an unfinished multistep operation, like graft, and abort
2330 if found. It's probably good to check this right before
2334 if found. It's probably good to check this right before
2331 bailifchanged().
2335 bailifchanged().
2332 '''
2336 '''
2333 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2337 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2334 if commit and allowcommit:
2338 if commit and allowcommit:
2335 continue
2339 continue
2336 if repo.vfs.exists(f):
2340 if repo.vfs.exists(f):
2337 raise util.Abort(msg, hint=hint)
2341 raise util.Abort(msg, hint=hint)
2338
2342
2339 def clearunfinished(repo):
2343 def clearunfinished(repo):
2340 '''Check for unfinished operations (as above), and clear the ones
2344 '''Check for unfinished operations (as above), and clear the ones
2341 that are clearable.
2345 that are clearable.
2342 '''
2346 '''
2343 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2347 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2344 if not clearable and repo.vfs.exists(f):
2348 if not clearable and repo.vfs.exists(f):
2345 raise util.Abort(msg, hint=hint)
2349 raise util.Abort(msg, hint=hint)
2346 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2350 for f, clearable, allowcommit, msg, hint in unfinishedstates:
2347 if clearable and repo.vfs.exists(f):
2351 if clearable and repo.vfs.exists(f):
2348 util.unlink(repo.join(f))
2352 util.unlink(repo.join(f))
@@ -1,5883 +1,5878 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
11 import os, re, difflib, time, tempfile, errno
12 import hg, scmutil, util, revlog, copies, error, bookmarks
12 import hg, scmutil, util, revlog, copies, error, bookmarks
13 import patch, help, encoding, templatekw, discovery
13 import patch, help, encoding, templatekw, discovery
14 import archival, changegroup, cmdutil, hbisect
14 import archival, changegroup, cmdutil, hbisect
15 import sshserver, hgweb, commandserver
15 import sshserver, hgweb, commandserver
16 from hgweb import server as hgweb_server
16 from hgweb import server as hgweb_server
17 import merge as mergemod
17 import merge as mergemod
18 import minirst, revset, fileset
18 import minirst, revset, fileset
19 import dagparser, context, simplemerge, graphmod
19 import dagparser, context, simplemerge, graphmod
20 import random
20 import random
21 import setdiscovery, treediscovery, dagutil, pvec, localrepo
21 import setdiscovery, treediscovery, dagutil, pvec, localrepo
22 import phases, obsolete
22 import phases, obsolete
23
23
24 table = {}
24 table = {}
25
25
26 command = cmdutil.command(table)
26 command = cmdutil.command(table)
27
27
28 # common command options
28 # common command options
29
29
30 globalopts = [
30 globalopts = [
31 ('R', 'repository', '',
31 ('R', 'repository', '',
32 _('repository root directory or name of overlay bundle file'),
32 _('repository root directory or name of overlay bundle file'),
33 _('REPO')),
33 _('REPO')),
34 ('', 'cwd', '',
34 ('', 'cwd', '',
35 _('change working directory'), _('DIR')),
35 _('change working directory'), _('DIR')),
36 ('y', 'noninteractive', None,
36 ('y', 'noninteractive', None,
37 _('do not prompt, automatically pick the first choice for all prompts')),
37 _('do not prompt, automatically pick the first choice for all prompts')),
38 ('q', 'quiet', None, _('suppress output')),
38 ('q', 'quiet', None, _('suppress output')),
39 ('v', 'verbose', None, _('enable additional output')),
39 ('v', 'verbose', None, _('enable additional output')),
40 ('', 'config', [],
40 ('', 'config', [],
41 _('set/override config option (use \'section.name=value\')'),
41 _('set/override config option (use \'section.name=value\')'),
42 _('CONFIG')),
42 _('CONFIG')),
43 ('', 'debug', None, _('enable debugging output')),
43 ('', 'debug', None, _('enable debugging output')),
44 ('', 'debugger', None, _('start debugger')),
44 ('', 'debugger', None, _('start debugger')),
45 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
45 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
46 _('ENCODE')),
46 _('ENCODE')),
47 ('', 'encodingmode', encoding.encodingmode,
47 ('', 'encodingmode', encoding.encodingmode,
48 _('set the charset encoding mode'), _('MODE')),
48 _('set the charset encoding mode'), _('MODE')),
49 ('', 'traceback', None, _('always print a traceback on exception')),
49 ('', 'traceback', None, _('always print a traceback on exception')),
50 ('', 'time', None, _('time how long the command takes')),
50 ('', 'time', None, _('time how long the command takes')),
51 ('', 'profile', None, _('print command execution profile')),
51 ('', 'profile', None, _('print command execution profile')),
52 ('', 'version', None, _('output version information and exit')),
52 ('', 'version', None, _('output version information and exit')),
53 ('h', 'help', None, _('display help and exit')),
53 ('h', 'help', None, _('display help and exit')),
54 ('', 'hidden', False, _('consider hidden changesets')),
54 ('', 'hidden', False, _('consider hidden changesets')),
55 ]
55 ]
56
56
57 dryrunopts = [('n', 'dry-run', None,
57 dryrunopts = [('n', 'dry-run', None,
58 _('do not perform actions, just print output'))]
58 _('do not perform actions, just print output'))]
59
59
60 remoteopts = [
60 remoteopts = [
61 ('e', 'ssh', '',
61 ('e', 'ssh', '',
62 _('specify ssh command to use'), _('CMD')),
62 _('specify ssh command to use'), _('CMD')),
63 ('', 'remotecmd', '',
63 ('', 'remotecmd', '',
64 _('specify hg command to run on the remote side'), _('CMD')),
64 _('specify hg command to run on the remote side'), _('CMD')),
65 ('', 'insecure', None,
65 ('', 'insecure', None,
66 _('do not verify server certificate (ignoring web.cacerts config)')),
66 _('do not verify server certificate (ignoring web.cacerts config)')),
67 ]
67 ]
68
68
69 walkopts = [
69 walkopts = [
70 ('I', 'include', [],
70 ('I', 'include', [],
71 _('include names matching the given patterns'), _('PATTERN')),
71 _('include names matching the given patterns'), _('PATTERN')),
72 ('X', 'exclude', [],
72 ('X', 'exclude', [],
73 _('exclude names matching the given patterns'), _('PATTERN')),
73 _('exclude names matching the given patterns'), _('PATTERN')),
74 ]
74 ]
75
75
76 commitopts = [
76 commitopts = [
77 ('m', 'message', '',
77 ('m', 'message', '',
78 _('use text as commit message'), _('TEXT')),
78 _('use text as commit message'), _('TEXT')),
79 ('l', 'logfile', '',
79 ('l', 'logfile', '',
80 _('read commit message from file'), _('FILE')),
80 _('read commit message from file'), _('FILE')),
81 ]
81 ]
82
82
83 commitopts2 = [
83 commitopts2 = [
84 ('d', 'date', '',
84 ('d', 'date', '',
85 _('record the specified date as commit date'), _('DATE')),
85 _('record the specified date as commit date'), _('DATE')),
86 ('u', 'user', '',
86 ('u', 'user', '',
87 _('record the specified user as committer'), _('USER')),
87 _('record the specified user as committer'), _('USER')),
88 ]
88 ]
89
89
90 templateopts = [
90 templateopts = [
91 ('', 'style', '',
91 ('', 'style', '',
92 _('display using template map file (DEPRECATED)'), _('STYLE')),
92 _('display using template map file (DEPRECATED)'), _('STYLE')),
93 ('T', 'template', '',
93 ('T', 'template', '',
94 _('display with template'), _('TEMPLATE')),
94 _('display with template'), _('TEMPLATE')),
95 ]
95 ]
96
96
97 logopts = [
97 logopts = [
98 ('p', 'patch', None, _('show patch')),
98 ('p', 'patch', None, _('show patch')),
99 ('g', 'git', None, _('use git extended diff format')),
99 ('g', 'git', None, _('use git extended diff format')),
100 ('l', 'limit', '',
100 ('l', 'limit', '',
101 _('limit number of changes displayed'), _('NUM')),
101 _('limit number of changes displayed'), _('NUM')),
102 ('M', 'no-merges', None, _('do not show merges')),
102 ('M', 'no-merges', None, _('do not show merges')),
103 ('', 'stat', None, _('output diffstat-style summary of changes')),
103 ('', 'stat', None, _('output diffstat-style summary of changes')),
104 ('G', 'graph', None, _("show the revision DAG")),
104 ('G', 'graph', None, _("show the revision DAG")),
105 ] + templateopts
105 ] + templateopts
106
106
107 diffopts = [
107 diffopts = [
108 ('a', 'text', None, _('treat all files as text')),
108 ('a', 'text', None, _('treat all files as text')),
109 ('g', 'git', None, _('use git extended diff format')),
109 ('g', 'git', None, _('use git extended diff format')),
110 ('', 'nodates', None, _('omit dates from diff headers'))
110 ('', 'nodates', None, _('omit dates from diff headers'))
111 ]
111 ]
112
112
113 diffwsopts = [
113 diffwsopts = [
114 ('w', 'ignore-all-space', None,
114 ('w', 'ignore-all-space', None,
115 _('ignore white space when comparing lines')),
115 _('ignore white space when comparing lines')),
116 ('b', 'ignore-space-change', None,
116 ('b', 'ignore-space-change', None,
117 _('ignore changes in the amount of white space')),
117 _('ignore changes in the amount of white space')),
118 ('B', 'ignore-blank-lines', None,
118 ('B', 'ignore-blank-lines', None,
119 _('ignore changes whose lines are all blank')),
119 _('ignore changes whose lines are all blank')),
120 ]
120 ]
121
121
122 diffopts2 = [
122 diffopts2 = [
123 ('p', 'show-function', None, _('show which function each change is in')),
123 ('p', 'show-function', None, _('show which function each change is in')),
124 ('', 'reverse', None, _('produce a diff that undoes the changes')),
124 ('', 'reverse', None, _('produce a diff that undoes the changes')),
125 ] + diffwsopts + [
125 ] + diffwsopts + [
126 ('U', 'unified', '',
126 ('U', 'unified', '',
127 _('number of lines of context to show'), _('NUM')),
127 _('number of lines of context to show'), _('NUM')),
128 ('', 'stat', None, _('output diffstat-style summary of changes')),
128 ('', 'stat', None, _('output diffstat-style summary of changes')),
129 ]
129 ]
130
130
131 mergetoolopts = [
131 mergetoolopts = [
132 ('t', 'tool', '', _('specify merge tool')),
132 ('t', 'tool', '', _('specify merge tool')),
133 ]
133 ]
134
134
135 similarityopts = [
135 similarityopts = [
136 ('s', 'similarity', '',
136 ('s', 'similarity', '',
137 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
137 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
138 ]
138 ]
139
139
140 subrepoopts = [
140 subrepoopts = [
141 ('S', 'subrepos', None,
141 ('S', 'subrepos', None,
142 _('recurse into subrepositories'))
142 _('recurse into subrepositories'))
143 ]
143 ]
144
144
145 # Commands start here, listed alphabetically
145 # Commands start here, listed alphabetically
146
146
147 @command('^add',
147 @command('^add',
148 walkopts + subrepoopts + dryrunopts,
148 walkopts + subrepoopts + dryrunopts,
149 _('[OPTION]... [FILE]...'))
149 _('[OPTION]... [FILE]...'))
150 def add(ui, repo, *pats, **opts):
150 def add(ui, repo, *pats, **opts):
151 """add the specified files on the next commit
151 """add the specified files on the next commit
152
152
153 Schedule files to be version controlled and added to the
153 Schedule files to be version controlled and added to the
154 repository.
154 repository.
155
155
156 The files will be added to the repository at the next commit. To
156 The files will be added to the repository at the next commit. To
157 undo an add before that, see :hg:`forget`.
157 undo an add before that, see :hg:`forget`.
158
158
159 If no names are given, add all files to the repository.
159 If no names are given, add all files to the repository.
160
160
161 .. container:: verbose
161 .. container:: verbose
162
162
163 An example showing how new (unknown) files are added
163 An example showing how new (unknown) files are added
164 automatically by :hg:`add`::
164 automatically by :hg:`add`::
165
165
166 $ ls
166 $ ls
167 foo.c
167 foo.c
168 $ hg status
168 $ hg status
169 ? foo.c
169 ? foo.c
170 $ hg add
170 $ hg add
171 adding foo.c
171 adding foo.c
172 $ hg status
172 $ hg status
173 A foo.c
173 A foo.c
174
174
175 Returns 0 if all files are successfully added.
175 Returns 0 if all files are successfully added.
176 """
176 """
177
177
178 m = scmutil.match(repo[None], pats, opts)
178 m = scmutil.match(repo[None], pats, opts)
179 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
179 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
180 opts.get('subrepos'), prefix="", explicitonly=False)
180 opts.get('subrepos'), prefix="", explicitonly=False)
181 return rejected and 1 or 0
181 return rejected and 1 or 0
182
182
183 @command('addremove',
183 @command('addremove',
184 similarityopts + walkopts + dryrunopts,
184 similarityopts + walkopts + dryrunopts,
185 _('[OPTION]... [FILE]...'))
185 _('[OPTION]... [FILE]...'))
186 def addremove(ui, repo, *pats, **opts):
186 def addremove(ui, repo, *pats, **opts):
187 """add all new files, delete all missing files
187 """add all new files, delete all missing files
188
188
189 Add all new files and remove all missing files from the
189 Add all new files and remove all missing files from the
190 repository.
190 repository.
191
191
192 New files are ignored if they match any of the patterns in
192 New files are ignored if they match any of the patterns in
193 ``.hgignore``. As with add, these changes take effect at the next
193 ``.hgignore``. As with add, these changes take effect at the next
194 commit.
194 commit.
195
195
196 Use the -s/--similarity option to detect renamed files. This
196 Use the -s/--similarity option to detect renamed files. This
197 option takes a percentage between 0 (disabled) and 100 (files must
197 option takes a percentage between 0 (disabled) and 100 (files must
198 be identical) as its parameter. With a parameter greater than 0,
198 be identical) as its parameter. With a parameter greater than 0,
199 this compares every removed file with every added file and records
199 this compares every removed file with every added file and records
200 those similar enough as renames. Detecting renamed files this way
200 those similar enough as renames. Detecting renamed files this way
201 can be expensive. After using this option, :hg:`status -C` can be
201 can be expensive. After using this option, :hg:`status -C` can be
202 used to check which files were identified as moved or renamed. If
202 used to check which files were identified as moved or renamed. If
203 not specified, -s/--similarity defaults to 100 and only renames of
203 not specified, -s/--similarity defaults to 100 and only renames of
204 identical files are detected.
204 identical files are detected.
205
205
206 Returns 0 if all files are successfully added.
206 Returns 0 if all files are successfully added.
207 """
207 """
208 try:
208 try:
209 sim = float(opts.get('similarity') or 100)
209 sim = float(opts.get('similarity') or 100)
210 except ValueError:
210 except ValueError:
211 raise util.Abort(_('similarity must be a number'))
211 raise util.Abort(_('similarity must be a number'))
212 if sim < 0 or sim > 100:
212 if sim < 0 or sim > 100:
213 raise util.Abort(_('similarity must be between 0 and 100'))
213 raise util.Abort(_('similarity must be between 0 and 100'))
214 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
214 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
215
215
216 @command('^annotate|blame',
216 @command('^annotate|blame',
217 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
217 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
218 ('', 'follow', None,
218 ('', 'follow', None,
219 _('follow copies/renames and list the filename (DEPRECATED)')),
219 _('follow copies/renames and list the filename (DEPRECATED)')),
220 ('', 'no-follow', None, _("don't follow copies and renames")),
220 ('', 'no-follow', None, _("don't follow copies and renames")),
221 ('a', 'text', None, _('treat all files as text')),
221 ('a', 'text', None, _('treat all files as text')),
222 ('u', 'user', None, _('list the author (long with -v)')),
222 ('u', 'user', None, _('list the author (long with -v)')),
223 ('f', 'file', None, _('list the filename')),
223 ('f', 'file', None, _('list the filename')),
224 ('d', 'date', None, _('list the date (short with -q)')),
224 ('d', 'date', None, _('list the date (short with -q)')),
225 ('n', 'number', None, _('list the revision number (default)')),
225 ('n', 'number', None, _('list the revision number (default)')),
226 ('c', 'changeset', None, _('list the changeset')),
226 ('c', 'changeset', None, _('list the changeset')),
227 ('l', 'line-number', None, _('show line number at the first appearance'))
227 ('l', 'line-number', None, _('show line number at the first appearance'))
228 ] + diffwsopts + walkopts,
228 ] + diffwsopts + walkopts,
229 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
229 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
230 def annotate(ui, repo, *pats, **opts):
230 def annotate(ui, repo, *pats, **opts):
231 """show changeset information by line for each file
231 """show changeset information by line for each file
232
232
233 List changes in files, showing the revision id responsible for
233 List changes in files, showing the revision id responsible for
234 each line
234 each line
235
235
236 This command is useful for discovering when a change was made and
236 This command is useful for discovering when a change was made and
237 by whom.
237 by whom.
238
238
239 Without the -a/--text option, annotate will avoid processing files
239 Without the -a/--text option, annotate will avoid processing files
240 it detects as binary. With -a, annotate will annotate the file
240 it detects as binary. With -a, annotate will annotate the file
241 anyway, although the results will probably be neither useful
241 anyway, although the results will probably be neither useful
242 nor desirable.
242 nor desirable.
243
243
244 Returns 0 on success.
244 Returns 0 on success.
245 """
245 """
246 if opts.get('follow'):
246 if opts.get('follow'):
247 # --follow is deprecated and now just an alias for -f/--file
247 # --follow is deprecated and now just an alias for -f/--file
248 # to mimic the behavior of Mercurial before version 1.5
248 # to mimic the behavior of Mercurial before version 1.5
249 opts['file'] = True
249 opts['file'] = True
250
250
251 datefunc = ui.quiet and util.shortdate or util.datestr
251 datefunc = ui.quiet and util.shortdate or util.datestr
252 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
252 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
253
253
254 if not pats:
254 if not pats:
255 raise util.Abort(_('at least one filename or pattern is required'))
255 raise util.Abort(_('at least one filename or pattern is required'))
256
256
257 hexfn = ui.debugflag and hex or short
257 hexfn = ui.debugflag and hex or short
258
258
259 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
259 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
260 ('number', ' ', lambda x: str(x[0].rev())),
260 ('number', ' ', lambda x: str(x[0].rev())),
261 ('changeset', ' ', lambda x: hexfn(x[0].node())),
261 ('changeset', ' ', lambda x: hexfn(x[0].node())),
262 ('date', ' ', getdate),
262 ('date', ' ', getdate),
263 ('file', ' ', lambda x: x[0].path()),
263 ('file', ' ', lambda x: x[0].path()),
264 ('line_number', ':', lambda x: str(x[1])),
264 ('line_number', ':', lambda x: str(x[1])),
265 ]
265 ]
266
266
267 if (not opts.get('user') and not opts.get('changeset')
267 if (not opts.get('user') and not opts.get('changeset')
268 and not opts.get('date') and not opts.get('file')):
268 and not opts.get('date') and not opts.get('file')):
269 opts['number'] = True
269 opts['number'] = True
270
270
271 linenumber = opts.get('line_number') is not None
271 linenumber = opts.get('line_number') is not None
272 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
272 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
273 raise util.Abort(_('at least one of -n/-c is required for -l'))
273 raise util.Abort(_('at least one of -n/-c is required for -l'))
274
274
275 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
275 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
276 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
276 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
277
277
278 def bad(x, y):
278 def bad(x, y):
279 raise util.Abort("%s: %s" % (x, y))
279 raise util.Abort("%s: %s" % (x, y))
280
280
281 ctx = scmutil.revsingle(repo, opts.get('rev'))
281 ctx = scmutil.revsingle(repo, opts.get('rev'))
282 m = scmutil.match(ctx, pats, opts)
282 m = scmutil.match(ctx, pats, opts)
283 m.bad = bad
283 m.bad = bad
284 follow = not opts.get('no_follow')
284 follow = not opts.get('no_follow')
285 diffopts = patch.diffopts(ui, opts, section='annotate')
285 diffopts = patch.diffopts(ui, opts, section='annotate')
286 for abs in ctx.walk(m):
286 for abs in ctx.walk(m):
287 fctx = ctx[abs]
287 fctx = ctx[abs]
288 if not opts.get('text') and util.binary(fctx.data()):
288 if not opts.get('text') and util.binary(fctx.data()):
289 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
289 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
290 continue
290 continue
291
291
292 lines = fctx.annotate(follow=follow, linenumber=linenumber,
292 lines = fctx.annotate(follow=follow, linenumber=linenumber,
293 diffopts=diffopts)
293 diffopts=diffopts)
294 pieces = []
294 pieces = []
295
295
296 for f, sep in funcmap:
296 for f, sep in funcmap:
297 l = [f(n) for n, dummy in lines]
297 l = [f(n) for n, dummy in lines]
298 if l:
298 if l:
299 sized = [(x, encoding.colwidth(x)) for x in l]
299 sized = [(x, encoding.colwidth(x)) for x in l]
300 ml = max([w for x, w in sized])
300 ml = max([w for x, w in sized])
301 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
301 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
302 for x, w in sized])
302 for x, w in sized])
303
303
304 if pieces:
304 if pieces:
305 for p, l in zip(zip(*pieces), lines):
305 for p, l in zip(zip(*pieces), lines):
306 ui.write("%s: %s" % ("".join(p), l[1]))
306 ui.write("%s: %s" % ("".join(p), l[1]))
307
307
308 if lines and not lines[-1][1].endswith('\n'):
308 if lines and not lines[-1][1].endswith('\n'):
309 ui.write('\n')
309 ui.write('\n')
310
310
311 @command('archive',
311 @command('archive',
312 [('', 'no-decode', None, _('do not pass files through decoders')),
312 [('', 'no-decode', None, _('do not pass files through decoders')),
313 ('p', 'prefix', '', _('directory prefix for files in archive'),
313 ('p', 'prefix', '', _('directory prefix for files in archive'),
314 _('PREFIX')),
314 _('PREFIX')),
315 ('r', 'rev', '', _('revision to distribute'), _('REV')),
315 ('r', 'rev', '', _('revision to distribute'), _('REV')),
316 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
316 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
317 ] + subrepoopts + walkopts,
317 ] + subrepoopts + walkopts,
318 _('[OPTION]... DEST'))
318 _('[OPTION]... DEST'))
319 def archive(ui, repo, dest, **opts):
319 def archive(ui, repo, dest, **opts):
320 '''create an unversioned archive of a repository revision
320 '''create an unversioned archive of a repository revision
321
321
322 By default, the revision used is the parent of the working
322 By default, the revision used is the parent of the working
323 directory; use -r/--rev to specify a different revision.
323 directory; use -r/--rev to specify a different revision.
324
324
325 The archive type is automatically detected based on file
325 The archive type is automatically detected based on file
326 extension (or override using -t/--type).
326 extension (or override using -t/--type).
327
327
328 .. container:: verbose
328 .. container:: verbose
329
329
330 Examples:
330 Examples:
331
331
332 - create a zip file containing the 1.0 release::
332 - create a zip file containing the 1.0 release::
333
333
334 hg archive -r 1.0 project-1.0.zip
334 hg archive -r 1.0 project-1.0.zip
335
335
336 - create a tarball excluding .hg files::
336 - create a tarball excluding .hg files::
337
337
338 hg archive project.tar.gz -X ".hg*"
338 hg archive project.tar.gz -X ".hg*"
339
339
340 Valid types are:
340 Valid types are:
341
341
342 :``files``: a directory full of files (default)
342 :``files``: a directory full of files (default)
343 :``tar``: tar archive, uncompressed
343 :``tar``: tar archive, uncompressed
344 :``tbz2``: tar archive, compressed using bzip2
344 :``tbz2``: tar archive, compressed using bzip2
345 :``tgz``: tar archive, compressed using gzip
345 :``tgz``: tar archive, compressed using gzip
346 :``uzip``: zip archive, uncompressed
346 :``uzip``: zip archive, uncompressed
347 :``zip``: zip archive, compressed using deflate
347 :``zip``: zip archive, compressed using deflate
348
348
349 The exact name of the destination archive or directory is given
349 The exact name of the destination archive or directory is given
350 using a format string; see :hg:`help export` for details.
350 using a format string; see :hg:`help export` for details.
351
351
352 Each member added to an archive file has a directory prefix
352 Each member added to an archive file has a directory prefix
353 prepended. Use -p/--prefix to specify a format string for the
353 prepended. Use -p/--prefix to specify a format string for the
354 prefix. The default is the basename of the archive, with suffixes
354 prefix. The default is the basename of the archive, with suffixes
355 removed.
355 removed.
356
356
357 Returns 0 on success.
357 Returns 0 on success.
358 '''
358 '''
359
359
360 ctx = scmutil.revsingle(repo, opts.get('rev'))
360 ctx = scmutil.revsingle(repo, opts.get('rev'))
361 if not ctx:
361 if not ctx:
362 raise util.Abort(_('no working directory: please specify a revision'))
362 raise util.Abort(_('no working directory: please specify a revision'))
363 node = ctx.node()
363 node = ctx.node()
364 dest = cmdutil.makefilename(repo, dest, node)
364 dest = cmdutil.makefilename(repo, dest, node)
365 if os.path.realpath(dest) == repo.root:
365 if os.path.realpath(dest) == repo.root:
366 raise util.Abort(_('repository root cannot be destination'))
366 raise util.Abort(_('repository root cannot be destination'))
367
367
368 kind = opts.get('type') or archival.guesskind(dest) or 'files'
368 kind = opts.get('type') or archival.guesskind(dest) or 'files'
369 prefix = opts.get('prefix')
369 prefix = opts.get('prefix')
370
370
371 if dest == '-':
371 if dest == '-':
372 if kind == 'files':
372 if kind == 'files':
373 raise util.Abort(_('cannot archive plain files to stdout'))
373 raise util.Abort(_('cannot archive plain files to stdout'))
374 dest = cmdutil.makefileobj(repo, dest)
374 dest = cmdutil.makefileobj(repo, dest)
375 if not prefix:
375 if not prefix:
376 prefix = os.path.basename(repo.root) + '-%h'
376 prefix = os.path.basename(repo.root) + '-%h'
377
377
378 prefix = cmdutil.makefilename(repo, prefix, node)
378 prefix = cmdutil.makefilename(repo, prefix, node)
379 matchfn = scmutil.match(ctx, [], opts)
379 matchfn = scmutil.match(ctx, [], opts)
380 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
380 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
381 matchfn, prefix, subrepos=opts.get('subrepos'))
381 matchfn, prefix, subrepos=opts.get('subrepos'))
382
382
383 @command('backout',
383 @command('backout',
384 [('', 'merge', None, _('merge with old dirstate parent after backout')),
384 [('', 'merge', None, _('merge with old dirstate parent after backout')),
385 ('', 'parent', '',
385 ('', 'parent', '',
386 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
386 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
387 ('r', 'rev', '', _('revision to backout'), _('REV')),
387 ('r', 'rev', '', _('revision to backout'), _('REV')),
388 ] + mergetoolopts + walkopts + commitopts + commitopts2,
388 ] + mergetoolopts + walkopts + commitopts + commitopts2,
389 _('[OPTION]... [-r] REV'))
389 _('[OPTION]... [-r] REV'))
390 def backout(ui, repo, node=None, rev=None, **opts):
390 def backout(ui, repo, node=None, rev=None, **opts):
391 '''reverse effect of earlier changeset
391 '''reverse effect of earlier changeset
392
392
393 Prepare a new changeset with the effect of REV undone in the
393 Prepare a new changeset with the effect of REV undone in the
394 current working directory.
394 current working directory.
395
395
396 If REV is the parent of the working directory, then this new changeset
396 If REV is the parent of the working directory, then this new changeset
397 is committed automatically. Otherwise, hg needs to merge the
397 is committed automatically. Otherwise, hg needs to merge the
398 changes and the merged result is left uncommitted.
398 changes and the merged result is left uncommitted.
399
399
400 .. note::
400 .. note::
401
401
402 backout cannot be used to fix either an unwanted or
402 backout cannot be used to fix either an unwanted or
403 incorrect merge.
403 incorrect merge.
404
404
405 .. container:: verbose
405 .. container:: verbose
406
406
407 By default, the pending changeset will have one parent,
407 By default, the pending changeset will have one parent,
408 maintaining a linear history. With --merge, the pending
408 maintaining a linear history. With --merge, the pending
409 changeset will instead have two parents: the old parent of the
409 changeset will instead have two parents: the old parent of the
410 working directory and a new child of REV that simply undoes REV.
410 working directory and a new child of REV that simply undoes REV.
411
411
412 Before version 1.7, the behavior without --merge was equivalent
412 Before version 1.7, the behavior without --merge was equivalent
413 to specifying --merge followed by :hg:`update --clean .` to
413 to specifying --merge followed by :hg:`update --clean .` to
414 cancel the merge and leave the child of REV as a head to be
414 cancel the merge and leave the child of REV as a head to be
415 merged separately.
415 merged separately.
416
416
417 See :hg:`help dates` for a list of formats valid for -d/--date.
417 See :hg:`help dates` for a list of formats valid for -d/--date.
418
418
419 Returns 0 on success.
419 Returns 0 on success.
420 '''
420 '''
421 if rev and node:
421 if rev and node:
422 raise util.Abort(_("please specify just one revision"))
422 raise util.Abort(_("please specify just one revision"))
423
423
424 if not rev:
424 if not rev:
425 rev = node
425 rev = node
426
426
427 if not rev:
427 if not rev:
428 raise util.Abort(_("please specify a revision to backout"))
428 raise util.Abort(_("please specify a revision to backout"))
429
429
430 date = opts.get('date')
430 date = opts.get('date')
431 if date:
431 if date:
432 opts['date'] = util.parsedate(date)
432 opts['date'] = util.parsedate(date)
433
433
434 cmdutil.checkunfinished(repo)
434 cmdutil.checkunfinished(repo)
435 cmdutil.bailifchanged(repo)
435 cmdutil.bailifchanged(repo)
436 node = scmutil.revsingle(repo, rev).node()
436 node = scmutil.revsingle(repo, rev).node()
437
437
438 op1, op2 = repo.dirstate.parents()
438 op1, op2 = repo.dirstate.parents()
439 a = repo.changelog.ancestor(op1, node)
439 a = repo.changelog.ancestor(op1, node)
440 if a != node:
440 if a != node:
441 raise util.Abort(_('cannot backout change on a different branch'))
441 raise util.Abort(_('cannot backout change on a different branch'))
442
442
443 p1, p2 = repo.changelog.parents(node)
443 p1, p2 = repo.changelog.parents(node)
444 if p1 == nullid:
444 if p1 == nullid:
445 raise util.Abort(_('cannot backout a change with no parents'))
445 raise util.Abort(_('cannot backout a change with no parents'))
446 if p2 != nullid:
446 if p2 != nullid:
447 if not opts.get('parent'):
447 if not opts.get('parent'):
448 raise util.Abort(_('cannot backout a merge changeset'))
448 raise util.Abort(_('cannot backout a merge changeset'))
449 p = repo.lookup(opts['parent'])
449 p = repo.lookup(opts['parent'])
450 if p not in (p1, p2):
450 if p not in (p1, p2):
451 raise util.Abort(_('%s is not a parent of %s') %
451 raise util.Abort(_('%s is not a parent of %s') %
452 (short(p), short(node)))
452 (short(p), short(node)))
453 parent = p
453 parent = p
454 else:
454 else:
455 if opts.get('parent'):
455 if opts.get('parent'):
456 raise util.Abort(_('cannot use --parent on non-merge changeset'))
456 raise util.Abort(_('cannot use --parent on non-merge changeset'))
457 parent = p1
457 parent = p1
458
458
459 # the backout should appear on the same branch
459 # the backout should appear on the same branch
460 wlock = repo.wlock()
460 wlock = repo.wlock()
461 try:
461 try:
462 branch = repo.dirstate.branch()
462 branch = repo.dirstate.branch()
463 bheads = repo.branchheads(branch)
463 bheads = repo.branchheads(branch)
464 rctx = scmutil.revsingle(repo, hex(parent))
464 rctx = scmutil.revsingle(repo, hex(parent))
465 if not opts.get('merge') and op1 != node:
465 if not opts.get('merge') and op1 != node:
466 try:
466 try:
467 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
467 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
468 stats = mergemod.update(repo, parent, True, True, False,
468 stats = mergemod.update(repo, parent, True, True, False,
469 node, False)
469 node, False)
470 repo.setparents(op1, op2)
470 repo.setparents(op1, op2)
471 hg._showstats(repo, stats)
471 hg._showstats(repo, stats)
472 if stats[3]:
472 if stats[3]:
473 repo.ui.status(_("use 'hg resolve' to retry unresolved "
473 repo.ui.status(_("use 'hg resolve' to retry unresolved "
474 "file merges\n"))
474 "file merges\n"))
475 else:
475 else:
476 msg = _("changeset %s backed out, "
476 msg = _("changeset %s backed out, "
477 "don't forget to commit.\n")
477 "don't forget to commit.\n")
478 ui.status(msg % short(node))
478 ui.status(msg % short(node))
479 return stats[3] > 0
479 return stats[3] > 0
480 finally:
480 finally:
481 ui.setconfig('ui', 'forcemerge', '')
481 ui.setconfig('ui', 'forcemerge', '')
482 else:
482 else:
483 hg.clean(repo, node, show_stats=False)
483 hg.clean(repo, node, show_stats=False)
484 repo.dirstate.setbranch(branch)
484 repo.dirstate.setbranch(branch)
485 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
485 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
486
486
487
487
488 e = cmdutil.commiteditor
488 e = cmdutil.commiteditor
489 if not opts['message'] and not opts['logfile']:
489 if not opts['message'] and not opts['logfile']:
490 # we don't translate commit messages
490 # we don't translate commit messages
491 opts['message'] = "Backed out changeset %s" % short(node)
491 opts['message'] = "Backed out changeset %s" % short(node)
492 e = cmdutil.commitforceeditor
492 e = cmdutil.commitforceeditor
493
493
494 def commitfunc(ui, repo, message, match, opts):
494 def commitfunc(ui, repo, message, match, opts):
495 return repo.commit(message, opts.get('user'), opts.get('date'),
495 return repo.commit(message, opts.get('user'), opts.get('date'),
496 match, editor=e)
496 match, editor=e)
497 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
497 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
498 cmdutil.commitstatus(repo, newnode, branch, bheads)
498 cmdutil.commitstatus(repo, newnode, branch, bheads)
499
499
500 def nice(node):
500 def nice(node):
501 return '%d:%s' % (repo.changelog.rev(node), short(node))
501 return '%d:%s' % (repo.changelog.rev(node), short(node))
502 ui.status(_('changeset %s backs out changeset %s\n') %
502 ui.status(_('changeset %s backs out changeset %s\n') %
503 (nice(repo.changelog.tip()), nice(node)))
503 (nice(repo.changelog.tip()), nice(node)))
504 if opts.get('merge') and op1 != node:
504 if opts.get('merge') and op1 != node:
505 hg.clean(repo, op1, show_stats=False)
505 hg.clean(repo, op1, show_stats=False)
506 ui.status(_('merging with changeset %s\n')
506 ui.status(_('merging with changeset %s\n')
507 % nice(repo.changelog.tip()))
507 % nice(repo.changelog.tip()))
508 try:
508 try:
509 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
509 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
510 return hg.merge(repo, hex(repo.changelog.tip()))
510 return hg.merge(repo, hex(repo.changelog.tip()))
511 finally:
511 finally:
512 ui.setconfig('ui', 'forcemerge', '')
512 ui.setconfig('ui', 'forcemerge', '')
513 finally:
513 finally:
514 wlock.release()
514 wlock.release()
515 return 0
515 return 0
516
516
517 @command('bisect',
517 @command('bisect',
518 [('r', 'reset', False, _('reset bisect state')),
518 [('r', 'reset', False, _('reset bisect state')),
519 ('g', 'good', False, _('mark changeset good')),
519 ('g', 'good', False, _('mark changeset good')),
520 ('b', 'bad', False, _('mark changeset bad')),
520 ('b', 'bad', False, _('mark changeset bad')),
521 ('s', 'skip', False, _('skip testing changeset')),
521 ('s', 'skip', False, _('skip testing changeset')),
522 ('e', 'extend', False, _('extend the bisect range')),
522 ('e', 'extend', False, _('extend the bisect range')),
523 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
523 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
524 ('U', 'noupdate', False, _('do not update to target'))],
524 ('U', 'noupdate', False, _('do not update to target'))],
525 _("[-gbsr] [-U] [-c CMD] [REV]"))
525 _("[-gbsr] [-U] [-c CMD] [REV]"))
526 def bisect(ui, repo, rev=None, extra=None, command=None,
526 def bisect(ui, repo, rev=None, extra=None, command=None,
527 reset=None, good=None, bad=None, skip=None, extend=None,
527 reset=None, good=None, bad=None, skip=None, extend=None,
528 noupdate=None):
528 noupdate=None):
529 """subdivision search of changesets
529 """subdivision search of changesets
530
530
531 This command helps to find changesets which introduce problems. To
531 This command helps to find changesets which introduce problems. To
532 use, mark the earliest changeset you know exhibits the problem as
532 use, mark the earliest changeset you know exhibits the problem as
533 bad, then mark the latest changeset which is free from the problem
533 bad, then mark the latest changeset which is free from the problem
534 as good. Bisect will update your working directory to a revision
534 as good. Bisect will update your working directory to a revision
535 for testing (unless the -U/--noupdate option is specified). Once
535 for testing (unless the -U/--noupdate option is specified). Once
536 you have performed tests, mark the working directory as good or
536 you have performed tests, mark the working directory as good or
537 bad, and bisect will either update to another candidate changeset
537 bad, and bisect will either update to another candidate changeset
538 or announce that it has found the bad revision.
538 or announce that it has found the bad revision.
539
539
540 As a shortcut, you can also use the revision argument to mark a
540 As a shortcut, you can also use the revision argument to mark a
541 revision as good or bad without checking it out first.
541 revision as good or bad without checking it out first.
542
542
543 If you supply a command, it will be used for automatic bisection.
543 If you supply a command, it will be used for automatic bisection.
544 The environment variable HG_NODE will contain the ID of the
544 The environment variable HG_NODE will contain the ID of the
545 changeset being tested. The exit status of the command will be
545 changeset being tested. The exit status of the command will be
546 used to mark revisions as good or bad: status 0 means good, 125
546 used to mark revisions as good or bad: status 0 means good, 125
547 means to skip the revision, 127 (command not found) will abort the
547 means to skip the revision, 127 (command not found) will abort the
548 bisection, and any other non-zero exit status means the revision
548 bisection, and any other non-zero exit status means the revision
549 is bad.
549 is bad.
550
550
551 .. container:: verbose
551 .. container:: verbose
552
552
553 Some examples:
553 Some examples:
554
554
555 - start a bisection with known bad revision 34, and good revision 12::
555 - start a bisection with known bad revision 34, and good revision 12::
556
556
557 hg bisect --bad 34
557 hg bisect --bad 34
558 hg bisect --good 12
558 hg bisect --good 12
559
559
560 - advance the current bisection by marking current revision as good or
560 - advance the current bisection by marking current revision as good or
561 bad::
561 bad::
562
562
563 hg bisect --good
563 hg bisect --good
564 hg bisect --bad
564 hg bisect --bad
565
565
566 - mark the current revision, or a known revision, to be skipped (e.g. if
566 - mark the current revision, or a known revision, to be skipped (e.g. if
567 that revision is not usable because of another issue)::
567 that revision is not usable because of another issue)::
568
568
569 hg bisect --skip
569 hg bisect --skip
570 hg bisect --skip 23
570 hg bisect --skip 23
571
571
572 - skip all revisions that do not touch directories ``foo`` or ``bar``::
572 - skip all revisions that do not touch directories ``foo`` or ``bar``::
573
573
574 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
574 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
575
575
576 - forget the current bisection::
576 - forget the current bisection::
577
577
578 hg bisect --reset
578 hg bisect --reset
579
579
580 - use 'make && make tests' to automatically find the first broken
580 - use 'make && make tests' to automatically find the first broken
581 revision::
581 revision::
582
582
583 hg bisect --reset
583 hg bisect --reset
584 hg bisect --bad 34
584 hg bisect --bad 34
585 hg bisect --good 12
585 hg bisect --good 12
586 hg bisect --command "make && make tests"
586 hg bisect --command "make && make tests"
587
587
588 - see all changesets whose states are already known in the current
588 - see all changesets whose states are already known in the current
589 bisection::
589 bisection::
590
590
591 hg log -r "bisect(pruned)"
591 hg log -r "bisect(pruned)"
592
592
593 - see the changeset currently being bisected (especially useful
593 - see the changeset currently being bisected (especially useful
594 if running with -U/--noupdate)::
594 if running with -U/--noupdate)::
595
595
596 hg log -r "bisect(current)"
596 hg log -r "bisect(current)"
597
597
598 - see all changesets that took part in the current bisection::
598 - see all changesets that took part in the current bisection::
599
599
600 hg log -r "bisect(range)"
600 hg log -r "bisect(range)"
601
601
602 - you can even get a nice graph::
602 - you can even get a nice graph::
603
603
604 hg log --graph -r "bisect(range)"
604 hg log --graph -r "bisect(range)"
605
605
606 See :hg:`help revsets` for more about the `bisect()` keyword.
606 See :hg:`help revsets` for more about the `bisect()` keyword.
607
607
608 Returns 0 on success.
608 Returns 0 on success.
609 """
609 """
610 def extendbisectrange(nodes, good):
610 def extendbisectrange(nodes, good):
611 # bisect is incomplete when it ends on a merge node and
611 # bisect is incomplete when it ends on a merge node and
612 # one of the parent was not checked.
612 # one of the parent was not checked.
613 parents = repo[nodes[0]].parents()
613 parents = repo[nodes[0]].parents()
614 if len(parents) > 1:
614 if len(parents) > 1:
615 side = good and state['bad'] or state['good']
615 side = good and state['bad'] or state['good']
616 num = len(set(i.node() for i in parents) & set(side))
616 num = len(set(i.node() for i in parents) & set(side))
617 if num == 1:
617 if num == 1:
618 return parents[0].ancestor(parents[1])
618 return parents[0].ancestor(parents[1])
619 return None
619 return None
620
620
621 def print_result(nodes, good):
621 def print_result(nodes, good):
622 displayer = cmdutil.show_changeset(ui, repo, {})
622 displayer = cmdutil.show_changeset(ui, repo, {})
623 if len(nodes) == 1:
623 if len(nodes) == 1:
624 # narrowed it down to a single revision
624 # narrowed it down to a single revision
625 if good:
625 if good:
626 ui.write(_("The first good revision is:\n"))
626 ui.write(_("The first good revision is:\n"))
627 else:
627 else:
628 ui.write(_("The first bad revision is:\n"))
628 ui.write(_("The first bad revision is:\n"))
629 displayer.show(repo[nodes[0]])
629 displayer.show(repo[nodes[0]])
630 extendnode = extendbisectrange(nodes, good)
630 extendnode = extendbisectrange(nodes, good)
631 if extendnode is not None:
631 if extendnode is not None:
632 ui.write(_('Not all ancestors of this changeset have been'
632 ui.write(_('Not all ancestors of this changeset have been'
633 ' checked.\nUse bisect --extend to continue the '
633 ' checked.\nUse bisect --extend to continue the '
634 'bisection from\nthe common ancestor, %s.\n')
634 'bisection from\nthe common ancestor, %s.\n')
635 % extendnode)
635 % extendnode)
636 else:
636 else:
637 # multiple possible revisions
637 # multiple possible revisions
638 if good:
638 if good:
639 ui.write(_("Due to skipped revisions, the first "
639 ui.write(_("Due to skipped revisions, the first "
640 "good revision could be any of:\n"))
640 "good revision could be any of:\n"))
641 else:
641 else:
642 ui.write(_("Due to skipped revisions, the first "
642 ui.write(_("Due to skipped revisions, the first "
643 "bad revision could be any of:\n"))
643 "bad revision could be any of:\n"))
644 for n in nodes:
644 for n in nodes:
645 displayer.show(repo[n])
645 displayer.show(repo[n])
646 displayer.close()
646 displayer.close()
647
647
648 def check_state(state, interactive=True):
648 def check_state(state, interactive=True):
649 if not state['good'] or not state['bad']:
649 if not state['good'] or not state['bad']:
650 if (good or bad or skip or reset) and interactive:
650 if (good or bad or skip or reset) and interactive:
651 return
651 return
652 if not state['good']:
652 if not state['good']:
653 raise util.Abort(_('cannot bisect (no known good revisions)'))
653 raise util.Abort(_('cannot bisect (no known good revisions)'))
654 else:
654 else:
655 raise util.Abort(_('cannot bisect (no known bad revisions)'))
655 raise util.Abort(_('cannot bisect (no known bad revisions)'))
656 return True
656 return True
657
657
658 # backward compatibility
658 # backward compatibility
659 if rev in "good bad reset init".split():
659 if rev in "good bad reset init".split():
660 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
660 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
661 cmd, rev, extra = rev, extra, None
661 cmd, rev, extra = rev, extra, None
662 if cmd == "good":
662 if cmd == "good":
663 good = True
663 good = True
664 elif cmd == "bad":
664 elif cmd == "bad":
665 bad = True
665 bad = True
666 else:
666 else:
667 reset = True
667 reset = True
668 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
668 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
669 raise util.Abort(_('incompatible arguments'))
669 raise util.Abort(_('incompatible arguments'))
670
670
671 cmdutil.checkunfinished(repo)
671 cmdutil.checkunfinished(repo)
672
672
673 if reset:
673 if reset:
674 p = repo.join("bisect.state")
674 p = repo.join("bisect.state")
675 if os.path.exists(p):
675 if os.path.exists(p):
676 os.unlink(p)
676 os.unlink(p)
677 return
677 return
678
678
679 state = hbisect.load_state(repo)
679 state = hbisect.load_state(repo)
680
680
681 if command:
681 if command:
682 changesets = 1
682 changesets = 1
683 if noupdate:
683 if noupdate:
684 try:
684 try:
685 node = state['current'][0]
685 node = state['current'][0]
686 except LookupError:
686 except LookupError:
687 raise util.Abort(_('current bisect revision is unknown - '
687 raise util.Abort(_('current bisect revision is unknown - '
688 'start a new bisect to fix'))
688 'start a new bisect to fix'))
689 else:
689 else:
690 node, p2 = repo.dirstate.parents()
690 node, p2 = repo.dirstate.parents()
691 if p2 != nullid:
691 if p2 != nullid:
692 raise util.Abort(_('current bisect revision is a merge'))
692 raise util.Abort(_('current bisect revision is a merge'))
693 try:
693 try:
694 while changesets:
694 while changesets:
695 # update state
695 # update state
696 state['current'] = [node]
696 state['current'] = [node]
697 hbisect.save_state(repo, state)
697 hbisect.save_state(repo, state)
698 status = util.system(command,
698 status = util.system(command,
699 environ={'HG_NODE': hex(node)},
699 environ={'HG_NODE': hex(node)},
700 out=ui.fout)
700 out=ui.fout)
701 if status == 125:
701 if status == 125:
702 transition = "skip"
702 transition = "skip"
703 elif status == 0:
703 elif status == 0:
704 transition = "good"
704 transition = "good"
705 # status < 0 means process was killed
705 # status < 0 means process was killed
706 elif status == 127:
706 elif status == 127:
707 raise util.Abort(_("failed to execute %s") % command)
707 raise util.Abort(_("failed to execute %s") % command)
708 elif status < 0:
708 elif status < 0:
709 raise util.Abort(_("%s killed") % command)
709 raise util.Abort(_("%s killed") % command)
710 else:
710 else:
711 transition = "bad"
711 transition = "bad"
712 ctx = scmutil.revsingle(repo, rev, node)
712 ctx = scmutil.revsingle(repo, rev, node)
713 rev = None # clear for future iterations
713 rev = None # clear for future iterations
714 state[transition].append(ctx.node())
714 state[transition].append(ctx.node())
715 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
715 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
716 check_state(state, interactive=False)
716 check_state(state, interactive=False)
717 # bisect
717 # bisect
718 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
718 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
719 # update to next check
719 # update to next check
720 node = nodes[0]
720 node = nodes[0]
721 if not noupdate:
721 if not noupdate:
722 cmdutil.bailifchanged(repo)
722 cmdutil.bailifchanged(repo)
723 hg.clean(repo, node, show_stats=False)
723 hg.clean(repo, node, show_stats=False)
724 finally:
724 finally:
725 state['current'] = [node]
725 state['current'] = [node]
726 hbisect.save_state(repo, state)
726 hbisect.save_state(repo, state)
727 print_result(nodes, bgood)
727 print_result(nodes, bgood)
728 return
728 return
729
729
730 # update state
730 # update state
731
731
732 if rev:
732 if rev:
733 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
733 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
734 else:
734 else:
735 nodes = [repo.lookup('.')]
735 nodes = [repo.lookup('.')]
736
736
737 if good or bad or skip:
737 if good or bad or skip:
738 if good:
738 if good:
739 state['good'] += nodes
739 state['good'] += nodes
740 elif bad:
740 elif bad:
741 state['bad'] += nodes
741 state['bad'] += nodes
742 elif skip:
742 elif skip:
743 state['skip'] += nodes
743 state['skip'] += nodes
744 hbisect.save_state(repo, state)
744 hbisect.save_state(repo, state)
745
745
746 if not check_state(state):
746 if not check_state(state):
747 return
747 return
748
748
749 # actually bisect
749 # actually bisect
750 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
750 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
751 if extend:
751 if extend:
752 if not changesets:
752 if not changesets:
753 extendnode = extendbisectrange(nodes, good)
753 extendnode = extendbisectrange(nodes, good)
754 if extendnode is not None:
754 if extendnode is not None:
755 ui.write(_("Extending search to changeset %d:%s\n"
755 ui.write(_("Extending search to changeset %d:%s\n"
756 % (extendnode.rev(), extendnode)))
756 % (extendnode.rev(), extendnode)))
757 state['current'] = [extendnode.node()]
757 state['current'] = [extendnode.node()]
758 hbisect.save_state(repo, state)
758 hbisect.save_state(repo, state)
759 if noupdate:
759 if noupdate:
760 return
760 return
761 cmdutil.bailifchanged(repo)
761 cmdutil.bailifchanged(repo)
762 return hg.clean(repo, extendnode.node())
762 return hg.clean(repo, extendnode.node())
763 raise util.Abort(_("nothing to extend"))
763 raise util.Abort(_("nothing to extend"))
764
764
765 if changesets == 0:
765 if changesets == 0:
766 print_result(nodes, good)
766 print_result(nodes, good)
767 else:
767 else:
768 assert len(nodes) == 1 # only a single node can be tested next
768 assert len(nodes) == 1 # only a single node can be tested next
769 node = nodes[0]
769 node = nodes[0]
770 # compute the approximate number of remaining tests
770 # compute the approximate number of remaining tests
771 tests, size = 0, 2
771 tests, size = 0, 2
772 while size <= changesets:
772 while size <= changesets:
773 tests, size = tests + 1, size * 2
773 tests, size = tests + 1, size * 2
774 rev = repo.changelog.rev(node)
774 rev = repo.changelog.rev(node)
775 ui.write(_("Testing changeset %d:%s "
775 ui.write(_("Testing changeset %d:%s "
776 "(%d changesets remaining, ~%d tests)\n")
776 "(%d changesets remaining, ~%d tests)\n")
777 % (rev, short(node), changesets, tests))
777 % (rev, short(node), changesets, tests))
778 state['current'] = [node]
778 state['current'] = [node]
779 hbisect.save_state(repo, state)
779 hbisect.save_state(repo, state)
780 if not noupdate:
780 if not noupdate:
781 cmdutil.bailifchanged(repo)
781 cmdutil.bailifchanged(repo)
782 return hg.clean(repo, node)
782 return hg.clean(repo, node)
783
783
784 @command('bookmarks|bookmark',
784 @command('bookmarks|bookmark',
785 [('f', 'force', False, _('force')),
785 [('f', 'force', False, _('force')),
786 ('r', 'rev', '', _('revision'), _('REV')),
786 ('r', 'rev', '', _('revision'), _('REV')),
787 ('d', 'delete', False, _('delete a given bookmark')),
787 ('d', 'delete', False, _('delete a given bookmark')),
788 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
788 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
789 ('i', 'inactive', False, _('mark a bookmark inactive'))],
789 ('i', 'inactive', False, _('mark a bookmark inactive'))],
790 _('hg bookmarks [OPTIONS]... [NAME]...'))
790 _('hg bookmarks [OPTIONS]... [NAME]...'))
791 def bookmark(ui, repo, *names, **opts):
791 def bookmark(ui, repo, *names, **opts):
792 '''track a line of development with movable markers
792 '''track a line of development with movable markers
793
793
794 Bookmarks are pointers to certain commits that move when committing.
794 Bookmarks are pointers to certain commits that move when committing.
795 Bookmarks are local. They can be renamed, copied and deleted. It is
795 Bookmarks are local. They can be renamed, copied and deleted. It is
796 possible to use :hg:`merge NAME` to merge from a given bookmark, and
796 possible to use :hg:`merge NAME` to merge from a given bookmark, and
797 :hg:`update NAME` to update to a given bookmark.
797 :hg:`update NAME` to update to a given bookmark.
798
798
799 You can use :hg:`bookmark NAME` to set a bookmark on the working
799 You can use :hg:`bookmark NAME` to set a bookmark on the working
800 directory's parent revision with the given name. If you specify
800 directory's parent revision with the given name. If you specify
801 a revision using -r REV (where REV may be an existing bookmark),
801 a revision using -r REV (where REV may be an existing bookmark),
802 the bookmark is assigned to that revision.
802 the bookmark is assigned to that revision.
803
803
804 Bookmarks can be pushed and pulled between repositories (see :hg:`help
804 Bookmarks can be pushed and pulled between repositories (see :hg:`help
805 push` and :hg:`help pull`). This requires both the local and remote
805 push` and :hg:`help pull`). This requires both the local and remote
806 repositories to support bookmarks. For versions prior to 1.8, this means
806 repositories to support bookmarks. For versions prior to 1.8, this means
807 the bookmarks extension must be enabled.
807 the bookmarks extension must be enabled.
808
808
809 If you set a bookmark called '@', new clones of the repository will
809 If you set a bookmark called '@', new clones of the repository will
810 have that revision checked out (and the bookmark made active) by
810 have that revision checked out (and the bookmark made active) by
811 default.
811 default.
812
812
813 With -i/--inactive, the new bookmark will not be made the active
813 With -i/--inactive, the new bookmark will not be made the active
814 bookmark. If -r/--rev is given, the new bookmark will not be made
814 bookmark. If -r/--rev is given, the new bookmark will not be made
815 active even if -i/--inactive is not given. If no NAME is given, the
815 active even if -i/--inactive is not given. If no NAME is given, the
816 current active bookmark will be marked inactive.
816 current active bookmark will be marked inactive.
817 '''
817 '''
818 force = opts.get('force')
818 force = opts.get('force')
819 rev = opts.get('rev')
819 rev = opts.get('rev')
820 delete = opts.get('delete')
820 delete = opts.get('delete')
821 rename = opts.get('rename')
821 rename = opts.get('rename')
822 inactive = opts.get('inactive')
822 inactive = opts.get('inactive')
823
823
824 def checkformat(mark):
824 def checkformat(mark):
825 mark = mark.strip()
825 mark = mark.strip()
826 if not mark:
826 if not mark:
827 raise util.Abort(_("bookmark names cannot consist entirely of "
827 raise util.Abort(_("bookmark names cannot consist entirely of "
828 "whitespace"))
828 "whitespace"))
829 scmutil.checknewlabel(repo, mark, 'bookmark')
829 scmutil.checknewlabel(repo, mark, 'bookmark')
830 return mark
830 return mark
831
831
832 def checkconflict(repo, mark, cur, force=False, target=None):
832 def checkconflict(repo, mark, cur, force=False, target=None):
833 if mark in marks and not force:
833 if mark in marks and not force:
834 if target:
834 if target:
835 if marks[mark] == target and target == cur:
835 if marks[mark] == target and target == cur:
836 # re-activating a bookmark
836 # re-activating a bookmark
837 return
837 return
838 anc = repo.changelog.ancestors([repo[target].rev()])
838 anc = repo.changelog.ancestors([repo[target].rev()])
839 bmctx = repo[marks[mark]]
839 bmctx = repo[marks[mark]]
840 divs = [repo[b].node() for b in marks
840 divs = [repo[b].node() for b in marks
841 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
841 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
842
842
843 # allow resolving a single divergent bookmark even if moving
843 # allow resolving a single divergent bookmark even if moving
844 # the bookmark across branches when a revision is specified
844 # the bookmark across branches when a revision is specified
845 # that contains a divergent bookmark
845 # that contains a divergent bookmark
846 if bmctx.rev() not in anc and target in divs:
846 if bmctx.rev() not in anc and target in divs:
847 bookmarks.deletedivergent(repo, [target], mark)
847 bookmarks.deletedivergent(repo, [target], mark)
848 return
848 return
849
849
850 deletefrom = [b for b in divs
850 deletefrom = [b for b in divs
851 if repo[b].rev() in anc or b == target]
851 if repo[b].rev() in anc or b == target]
852 bookmarks.deletedivergent(repo, deletefrom, mark)
852 bookmarks.deletedivergent(repo, deletefrom, mark)
853 if bookmarks.validdest(repo, bmctx, repo[target]):
853 if bookmarks.validdest(repo, bmctx, repo[target]):
854 ui.status(_("moving bookmark '%s' forward from %s\n") %
854 ui.status(_("moving bookmark '%s' forward from %s\n") %
855 (mark, short(bmctx.node())))
855 (mark, short(bmctx.node())))
856 return
856 return
857 raise util.Abort(_("bookmark '%s' already exists "
857 raise util.Abort(_("bookmark '%s' already exists "
858 "(use -f to force)") % mark)
858 "(use -f to force)") % mark)
859 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
859 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
860 and not force):
860 and not force):
861 raise util.Abort(
861 raise util.Abort(
862 _("a bookmark cannot have the name of an existing branch"))
862 _("a bookmark cannot have the name of an existing branch"))
863
863
864 if delete and rename:
864 if delete and rename:
865 raise util.Abort(_("--delete and --rename are incompatible"))
865 raise util.Abort(_("--delete and --rename are incompatible"))
866 if delete and rev:
866 if delete and rev:
867 raise util.Abort(_("--rev is incompatible with --delete"))
867 raise util.Abort(_("--rev is incompatible with --delete"))
868 if rename and rev:
868 if rename and rev:
869 raise util.Abort(_("--rev is incompatible with --rename"))
869 raise util.Abort(_("--rev is incompatible with --rename"))
870 if not names and (delete or rev):
870 if not names and (delete or rev):
871 raise util.Abort(_("bookmark name required"))
871 raise util.Abort(_("bookmark name required"))
872
872
873 if delete or rename or names or inactive:
873 if delete or rename or names or inactive:
874 wlock = repo.wlock()
874 wlock = repo.wlock()
875 try:
875 try:
876 cur = repo.changectx('.').node()
876 cur = repo.changectx('.').node()
877 marks = repo._bookmarks
877 marks = repo._bookmarks
878 if delete:
878 if delete:
879 for mark in names:
879 for mark in names:
880 if mark not in marks:
880 if mark not in marks:
881 raise util.Abort(_("bookmark '%s' does not exist") %
881 raise util.Abort(_("bookmark '%s' does not exist") %
882 mark)
882 mark)
883 if mark == repo._bookmarkcurrent:
883 if mark == repo._bookmarkcurrent:
884 bookmarks.unsetcurrent(repo)
884 bookmarks.unsetcurrent(repo)
885 del marks[mark]
885 del marks[mark]
886 marks.write()
886 marks.write()
887
887
888 elif rename:
888 elif rename:
889 if not names:
889 if not names:
890 raise util.Abort(_("new bookmark name required"))
890 raise util.Abort(_("new bookmark name required"))
891 elif len(names) > 1:
891 elif len(names) > 1:
892 raise util.Abort(_("only one new bookmark name allowed"))
892 raise util.Abort(_("only one new bookmark name allowed"))
893 mark = checkformat(names[0])
893 mark = checkformat(names[0])
894 if rename not in marks:
894 if rename not in marks:
895 raise util.Abort(_("bookmark '%s' does not exist") % rename)
895 raise util.Abort(_("bookmark '%s' does not exist") % rename)
896 checkconflict(repo, mark, cur, force)
896 checkconflict(repo, mark, cur, force)
897 marks[mark] = marks[rename]
897 marks[mark] = marks[rename]
898 if repo._bookmarkcurrent == rename and not inactive:
898 if repo._bookmarkcurrent == rename and not inactive:
899 bookmarks.setcurrent(repo, mark)
899 bookmarks.setcurrent(repo, mark)
900 del marks[rename]
900 del marks[rename]
901 marks.write()
901 marks.write()
902
902
903 elif names:
903 elif names:
904 newact = None
904 newact = None
905 for mark in names:
905 for mark in names:
906 mark = checkformat(mark)
906 mark = checkformat(mark)
907 if newact is None:
907 if newact is None:
908 newact = mark
908 newact = mark
909 if inactive and mark == repo._bookmarkcurrent:
909 if inactive and mark == repo._bookmarkcurrent:
910 bookmarks.unsetcurrent(repo)
910 bookmarks.unsetcurrent(repo)
911 return
911 return
912 tgt = cur
912 tgt = cur
913 if rev:
913 if rev:
914 tgt = scmutil.revsingle(repo, rev).node()
914 tgt = scmutil.revsingle(repo, rev).node()
915 checkconflict(repo, mark, cur, force, tgt)
915 checkconflict(repo, mark, cur, force, tgt)
916 marks[mark] = tgt
916 marks[mark] = tgt
917 if not inactive and cur == marks[newact] and not rev:
917 if not inactive and cur == marks[newact] and not rev:
918 bookmarks.setcurrent(repo, newact)
918 bookmarks.setcurrent(repo, newact)
919 elif cur != tgt and newact == repo._bookmarkcurrent:
919 elif cur != tgt and newact == repo._bookmarkcurrent:
920 bookmarks.unsetcurrent(repo)
920 bookmarks.unsetcurrent(repo)
921 marks.write()
921 marks.write()
922
922
923 elif inactive:
923 elif inactive:
924 if len(marks) == 0:
924 if len(marks) == 0:
925 ui.status(_("no bookmarks set\n"))
925 ui.status(_("no bookmarks set\n"))
926 elif not repo._bookmarkcurrent:
926 elif not repo._bookmarkcurrent:
927 ui.status(_("no active bookmark\n"))
927 ui.status(_("no active bookmark\n"))
928 else:
928 else:
929 bookmarks.unsetcurrent(repo)
929 bookmarks.unsetcurrent(repo)
930 finally:
930 finally:
931 wlock.release()
931 wlock.release()
932 else: # show bookmarks
932 else: # show bookmarks
933 hexfn = ui.debugflag and hex or short
933 hexfn = ui.debugflag and hex or short
934 marks = repo._bookmarks
934 marks = repo._bookmarks
935 if len(marks) == 0:
935 if len(marks) == 0:
936 ui.status(_("no bookmarks set\n"))
936 ui.status(_("no bookmarks set\n"))
937 else:
937 else:
938 for bmark, n in sorted(marks.iteritems()):
938 for bmark, n in sorted(marks.iteritems()):
939 current = repo._bookmarkcurrent
939 current = repo._bookmarkcurrent
940 if bmark == current:
940 if bmark == current:
941 prefix, label = '*', 'bookmarks.current'
941 prefix, label = '*', 'bookmarks.current'
942 else:
942 else:
943 prefix, label = ' ', ''
943 prefix, label = ' ', ''
944
944
945 if ui.quiet:
945 if ui.quiet:
946 ui.write("%s\n" % bmark, label=label)
946 ui.write("%s\n" % bmark, label=label)
947 else:
947 else:
948 ui.write(" %s %-25s %d:%s\n" % (
948 ui.write(" %s %-25s %d:%s\n" % (
949 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
949 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
950 label=label)
950 label=label)
951
951
952 @command('branch',
952 @command('branch',
953 [('f', 'force', None,
953 [('f', 'force', None,
954 _('set branch name even if it shadows an existing branch')),
954 _('set branch name even if it shadows an existing branch')),
955 ('C', 'clean', None, _('reset branch name to parent branch name'))],
955 ('C', 'clean', None, _('reset branch name to parent branch name'))],
956 _('[-fC] [NAME]'))
956 _('[-fC] [NAME]'))
957 def branch(ui, repo, label=None, **opts):
957 def branch(ui, repo, label=None, **opts):
958 """set or show the current branch name
958 """set or show the current branch name
959
959
960 .. note::
960 .. note::
961
961
962 Branch names are permanent and global. Use :hg:`bookmark` to create a
962 Branch names are permanent and global. Use :hg:`bookmark` to create a
963 light-weight bookmark instead. See :hg:`help glossary` for more
963 light-weight bookmark instead. See :hg:`help glossary` for more
964 information about named branches and bookmarks.
964 information about named branches and bookmarks.
965
965
966 With no argument, show the current branch name. With one argument,
966 With no argument, show the current branch name. With one argument,
967 set the working directory branch name (the branch will not exist
967 set the working directory branch name (the branch will not exist
968 in the repository until the next commit). Standard practice
968 in the repository until the next commit). Standard practice
969 recommends that primary development take place on the 'default'
969 recommends that primary development take place on the 'default'
970 branch.
970 branch.
971
971
972 Unless -f/--force is specified, branch will not let you set a
972 Unless -f/--force is specified, branch will not let you set a
973 branch name that already exists, even if it's inactive.
973 branch name that already exists, even if it's inactive.
974
974
975 Use -C/--clean to reset the working directory branch to that of
975 Use -C/--clean to reset the working directory branch to that of
976 the parent of the working directory, negating a previous branch
976 the parent of the working directory, negating a previous branch
977 change.
977 change.
978
978
979 Use the command :hg:`update` to switch to an existing branch. Use
979 Use the command :hg:`update` to switch to an existing branch. Use
980 :hg:`commit --close-branch` to mark this branch as closed.
980 :hg:`commit --close-branch` to mark this branch as closed.
981
981
982 Returns 0 on success.
982 Returns 0 on success.
983 """
983 """
984 if label:
984 if label:
985 label = label.strip()
985 label = label.strip()
986
986
987 if not opts.get('clean') and not label:
987 if not opts.get('clean') and not label:
988 ui.write("%s\n" % repo.dirstate.branch())
988 ui.write("%s\n" % repo.dirstate.branch())
989 return
989 return
990
990
991 wlock = repo.wlock()
991 wlock = repo.wlock()
992 try:
992 try:
993 if opts.get('clean'):
993 if opts.get('clean'):
994 label = repo[None].p1().branch()
994 label = repo[None].p1().branch()
995 repo.dirstate.setbranch(label)
995 repo.dirstate.setbranch(label)
996 ui.status(_('reset working directory to branch %s\n') % label)
996 ui.status(_('reset working directory to branch %s\n') % label)
997 elif label:
997 elif label:
998 if not opts.get('force') and label in repo.branchmap():
998 if not opts.get('force') and label in repo.branchmap():
999 if label not in [p.branch() for p in repo.parents()]:
999 if label not in [p.branch() for p in repo.parents()]:
1000 raise util.Abort(_('a branch of the same name already'
1000 raise util.Abort(_('a branch of the same name already'
1001 ' exists'),
1001 ' exists'),
1002 # i18n: "it" refers to an existing branch
1002 # i18n: "it" refers to an existing branch
1003 hint=_("use 'hg update' to switch to it"))
1003 hint=_("use 'hg update' to switch to it"))
1004 scmutil.checknewlabel(repo, label, 'branch')
1004 scmutil.checknewlabel(repo, label, 'branch')
1005 repo.dirstate.setbranch(label)
1005 repo.dirstate.setbranch(label)
1006 ui.status(_('marked working directory as branch %s\n') % label)
1006 ui.status(_('marked working directory as branch %s\n') % label)
1007 ui.status(_('(branches are permanent and global, '
1007 ui.status(_('(branches are permanent and global, '
1008 'did you want a bookmark?)\n'))
1008 'did you want a bookmark?)\n'))
1009 finally:
1009 finally:
1010 wlock.release()
1010 wlock.release()
1011
1011
1012 @command('branches',
1012 @command('branches',
1013 [('a', 'active', False, _('show only branches that have unmerged heads')),
1013 [('a', 'active', False, _('show only branches that have unmerged heads')),
1014 ('c', 'closed', False, _('show normal and closed branches'))],
1014 ('c', 'closed', False, _('show normal and closed branches'))],
1015 _('[-ac]'))
1015 _('[-ac]'))
1016 def branches(ui, repo, active=False, closed=False):
1016 def branches(ui, repo, active=False, closed=False):
1017 """list repository named branches
1017 """list repository named branches
1018
1018
1019 List the repository's named branches, indicating which ones are
1019 List the repository's named branches, indicating which ones are
1020 inactive. If -c/--closed is specified, also list branches which have
1020 inactive. If -c/--closed is specified, also list branches which have
1021 been marked closed (see :hg:`commit --close-branch`).
1021 been marked closed (see :hg:`commit --close-branch`).
1022
1022
1023 If -a/--active is specified, only show active branches. A branch
1023 If -a/--active is specified, only show active branches. A branch
1024 is considered active if it contains repository heads.
1024 is considered active if it contains repository heads.
1025
1025
1026 Use the command :hg:`update` to switch to an existing branch.
1026 Use the command :hg:`update` to switch to an existing branch.
1027
1027
1028 Returns 0.
1028 Returns 0.
1029 """
1029 """
1030
1030
1031 hexfunc = ui.debugflag and hex or short
1031 hexfunc = ui.debugflag and hex or short
1032
1032
1033 allheads = set(repo.heads())
1033 allheads = set(repo.heads())
1034 branches = []
1034 branches = []
1035 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1035 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1036 isactive = not isclosed and bool(set(heads) & allheads)
1036 isactive = not isclosed and bool(set(heads) & allheads)
1037 branches.append((tag, repo[tip], isactive, not isclosed))
1037 branches.append((tag, repo[tip], isactive, not isclosed))
1038 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1038 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1039 reverse=True)
1039 reverse=True)
1040
1040
1041 for tag, ctx, isactive, isopen in branches:
1041 for tag, ctx, isactive, isopen in branches:
1042 if (not active) or isactive:
1042 if (not active) or isactive:
1043 if isactive:
1043 if isactive:
1044 label = 'branches.active'
1044 label = 'branches.active'
1045 notice = ''
1045 notice = ''
1046 elif not isopen:
1046 elif not isopen:
1047 if not closed:
1047 if not closed:
1048 continue
1048 continue
1049 label = 'branches.closed'
1049 label = 'branches.closed'
1050 notice = _(' (closed)')
1050 notice = _(' (closed)')
1051 else:
1051 else:
1052 label = 'branches.inactive'
1052 label = 'branches.inactive'
1053 notice = _(' (inactive)')
1053 notice = _(' (inactive)')
1054 if tag == repo.dirstate.branch():
1054 if tag == repo.dirstate.branch():
1055 label = 'branches.current'
1055 label = 'branches.current'
1056 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(tag))
1056 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(tag))
1057 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
1057 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
1058 'log.changeset changeset.%s' % ctx.phasestr())
1058 'log.changeset changeset.%s' % ctx.phasestr())
1059 labeledtag = ui.label(tag, label)
1059 labeledtag = ui.label(tag, label)
1060 if ui.quiet:
1060 if ui.quiet:
1061 ui.write("%s\n" % labeledtag)
1061 ui.write("%s\n" % labeledtag)
1062 else:
1062 else:
1063 ui.write("%s %s%s\n" % (labeledtag, rev, notice))
1063 ui.write("%s %s%s\n" % (labeledtag, rev, notice))
1064
1064
1065 @command('bundle',
1065 @command('bundle',
1066 [('f', 'force', None, _('run even when the destination is unrelated')),
1066 [('f', 'force', None, _('run even when the destination is unrelated')),
1067 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1067 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1068 _('REV')),
1068 _('REV')),
1069 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1069 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1070 _('BRANCH')),
1070 _('BRANCH')),
1071 ('', 'base', [],
1071 ('', 'base', [],
1072 _('a base changeset assumed to be available at the destination'),
1072 _('a base changeset assumed to be available at the destination'),
1073 _('REV')),
1073 _('REV')),
1074 ('a', 'all', None, _('bundle all changesets in the repository')),
1074 ('a', 'all', None, _('bundle all changesets in the repository')),
1075 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1075 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1076 ] + remoteopts,
1076 ] + remoteopts,
1077 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1077 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1078 def bundle(ui, repo, fname, dest=None, **opts):
1078 def bundle(ui, repo, fname, dest=None, **opts):
1079 """create a changegroup file
1079 """create a changegroup file
1080
1080
1081 Generate a compressed changegroup file collecting changesets not
1081 Generate a compressed changegroup file collecting changesets not
1082 known to be in another repository.
1082 known to be in another repository.
1083
1083
1084 If you omit the destination repository, then hg assumes the
1084 If you omit the destination repository, then hg assumes the
1085 destination will have all the nodes you specify with --base
1085 destination will have all the nodes you specify with --base
1086 parameters. To create a bundle containing all changesets, use
1086 parameters. To create a bundle containing all changesets, use
1087 -a/--all (or --base null).
1087 -a/--all (or --base null).
1088
1088
1089 You can change compression method with the -t/--type option.
1089 You can change compression method with the -t/--type option.
1090 The available compression methods are: none, bzip2, and
1090 The available compression methods are: none, bzip2, and
1091 gzip (by default, bundles are compressed using bzip2).
1091 gzip (by default, bundles are compressed using bzip2).
1092
1092
1093 The bundle file can then be transferred using conventional means
1093 The bundle file can then be transferred using conventional means
1094 and applied to another repository with the unbundle or pull
1094 and applied to another repository with the unbundle or pull
1095 command. This is useful when direct push and pull are not
1095 command. This is useful when direct push and pull are not
1096 available or when exporting an entire repository is undesirable.
1096 available or when exporting an entire repository is undesirable.
1097
1097
1098 Applying bundles preserves all changeset contents including
1098 Applying bundles preserves all changeset contents including
1099 permissions, copy/rename information, and revision history.
1099 permissions, copy/rename information, and revision history.
1100
1100
1101 Returns 0 on success, 1 if no changes found.
1101 Returns 0 on success, 1 if no changes found.
1102 """
1102 """
1103 revs = None
1103 revs = None
1104 if 'rev' in opts:
1104 if 'rev' in opts:
1105 revs = scmutil.revrange(repo, opts['rev'])
1105 revs = scmutil.revrange(repo, opts['rev'])
1106
1106
1107 bundletype = opts.get('type', 'bzip2').lower()
1107 bundletype = opts.get('type', 'bzip2').lower()
1108 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1108 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1109 bundletype = btypes.get(bundletype)
1109 bundletype = btypes.get(bundletype)
1110 if bundletype not in changegroup.bundletypes:
1110 if bundletype not in changegroup.bundletypes:
1111 raise util.Abort(_('unknown bundle type specified with --type'))
1111 raise util.Abort(_('unknown bundle type specified with --type'))
1112
1112
1113 if opts.get('all'):
1113 if opts.get('all'):
1114 base = ['null']
1114 base = ['null']
1115 else:
1115 else:
1116 base = scmutil.revrange(repo, opts.get('base'))
1116 base = scmutil.revrange(repo, opts.get('base'))
1117 # TODO: get desired bundlecaps from command line.
1117 # TODO: get desired bundlecaps from command line.
1118 bundlecaps = None
1118 bundlecaps = None
1119 if base:
1119 if base:
1120 if dest:
1120 if dest:
1121 raise util.Abort(_("--base is incompatible with specifying "
1121 raise util.Abort(_("--base is incompatible with specifying "
1122 "a destination"))
1122 "a destination"))
1123 common = [repo.lookup(rev) for rev in base]
1123 common = [repo.lookup(rev) for rev in base]
1124 heads = revs and map(repo.lookup, revs) or revs
1124 heads = revs and map(repo.lookup, revs) or revs
1125 cg = repo.getbundle('bundle', heads=heads, common=common,
1125 cg = repo.getbundle('bundle', heads=heads, common=common,
1126 bundlecaps=bundlecaps)
1126 bundlecaps=bundlecaps)
1127 outgoing = None
1127 outgoing = None
1128 else:
1128 else:
1129 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1129 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1130 dest, branches = hg.parseurl(dest, opts.get('branch'))
1130 dest, branches = hg.parseurl(dest, opts.get('branch'))
1131 other = hg.peer(repo, opts, dest)
1131 other = hg.peer(repo, opts, dest)
1132 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1132 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1133 heads = revs and map(repo.lookup, revs) or revs
1133 heads = revs and map(repo.lookup, revs) or revs
1134 outgoing = discovery.findcommonoutgoing(repo, other,
1134 outgoing = discovery.findcommonoutgoing(repo, other,
1135 onlyheads=heads,
1135 onlyheads=heads,
1136 force=opts.get('force'),
1136 force=opts.get('force'),
1137 portable=True)
1137 portable=True)
1138 cg = repo.getlocalbundle('bundle', outgoing, bundlecaps)
1138 cg = repo.getlocalbundle('bundle', outgoing, bundlecaps)
1139 if not cg:
1139 if not cg:
1140 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1140 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1141 return 1
1141 return 1
1142
1142
1143 changegroup.writebundle(cg, fname, bundletype)
1143 changegroup.writebundle(cg, fname, bundletype)
1144
1144
1145 @command('cat',
1145 @command('cat',
1146 [('o', 'output', '',
1146 [('o', 'output', '',
1147 _('print output to file with formatted name'), _('FORMAT')),
1147 _('print output to file with formatted name'), _('FORMAT')),
1148 ('r', 'rev', '', _('print the given revision'), _('REV')),
1148 ('r', 'rev', '', _('print the given revision'), _('REV')),
1149 ('', 'decode', None, _('apply any matching decode filter')),
1149 ('', 'decode', None, _('apply any matching decode filter')),
1150 ] + walkopts,
1150 ] + walkopts,
1151 _('[OPTION]... FILE...'))
1151 _('[OPTION]... FILE...'))
1152 def cat(ui, repo, file1, *pats, **opts):
1152 def cat(ui, repo, file1, *pats, **opts):
1153 """output the current or given revision of files
1153 """output the current or given revision of files
1154
1154
1155 Print the specified files as they were at the given revision. If
1155 Print the specified files as they were at the given revision. If
1156 no revision is given, the parent of the working directory is used.
1156 no revision is given, the parent of the working directory is used.
1157
1157
1158 Output may be to a file, in which case the name of the file is
1158 Output may be to a file, in which case the name of the file is
1159 given using a format string. The formatting rules are the same as
1159 given using a format string. The formatting rules are the same as
1160 for the export command, with the following additions:
1160 for the export command, with the following additions:
1161
1161
1162 :``%s``: basename of file being printed
1162 :``%s``: basename of file being printed
1163 :``%d``: dirname of file being printed, or '.' if in repository root
1163 :``%d``: dirname of file being printed, or '.' if in repository root
1164 :``%p``: root-relative path name of file being printed
1164 :``%p``: root-relative path name of file being printed
1165
1165
1166 Returns 0 on success.
1166 Returns 0 on success.
1167 """
1167 """
1168 ctx = scmutil.revsingle(repo, opts.get('rev'))
1168 ctx = scmutil.revsingle(repo, opts.get('rev'))
1169 err = 1
1169 err = 1
1170 m = scmutil.match(ctx, (file1,) + pats, opts)
1170 m = scmutil.match(ctx, (file1,) + pats, opts)
1171
1171
1172 def write(path):
1172 def write(path):
1173 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1173 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1174 pathname=path)
1174 pathname=path)
1175 data = ctx[path].data()
1175 data = ctx[path].data()
1176 if opts.get('decode'):
1176 if opts.get('decode'):
1177 data = repo.wwritedata(path, data)
1177 data = repo.wwritedata(path, data)
1178 fp.write(data)
1178 fp.write(data)
1179 fp.close()
1179 fp.close()
1180
1180
1181 # Automation often uses hg cat on single files, so special case it
1181 # Automation often uses hg cat on single files, so special case it
1182 # for performance to avoid the cost of parsing the manifest.
1182 # for performance to avoid the cost of parsing the manifest.
1183 if len(m.files()) == 1 and not m.anypats():
1183 if len(m.files()) == 1 and not m.anypats():
1184 file = m.files()[0]
1184 file = m.files()[0]
1185 mf = repo.manifest
1185 mf = repo.manifest
1186 mfnode = ctx._changeset[0]
1186 mfnode = ctx._changeset[0]
1187 if mf.find(mfnode, file)[0]:
1187 if mf.find(mfnode, file)[0]:
1188 write(file)
1188 write(file)
1189 return 0
1189 return 0
1190
1190
1191 for abs in ctx.walk(m):
1191 for abs in ctx.walk(m):
1192 write(abs)
1192 write(abs)
1193 err = 0
1193 err = 0
1194 return err
1194 return err
1195
1195
1196 @command('^clone',
1196 @command('^clone',
1197 [('U', 'noupdate', None,
1197 [('U', 'noupdate', None,
1198 _('the clone will include an empty working copy (only a repository)')),
1198 _('the clone will include an empty working copy (only a repository)')),
1199 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1199 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1200 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1200 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1201 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1201 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1202 ('', 'pull', None, _('use pull protocol to copy metadata')),
1202 ('', 'pull', None, _('use pull protocol to copy metadata')),
1203 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1203 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1204 ] + remoteopts,
1204 ] + remoteopts,
1205 _('[OPTION]... SOURCE [DEST]'))
1205 _('[OPTION]... SOURCE [DEST]'))
1206 def clone(ui, source, dest=None, **opts):
1206 def clone(ui, source, dest=None, **opts):
1207 """make a copy of an existing repository
1207 """make a copy of an existing repository
1208
1208
1209 Create a copy of an existing repository in a new directory.
1209 Create a copy of an existing repository in a new directory.
1210
1210
1211 If no destination directory name is specified, it defaults to the
1211 If no destination directory name is specified, it defaults to the
1212 basename of the source.
1212 basename of the source.
1213
1213
1214 The location of the source is added to the new repository's
1214 The location of the source is added to the new repository's
1215 ``.hg/hgrc`` file, as the default to be used for future pulls.
1215 ``.hg/hgrc`` file, as the default to be used for future pulls.
1216
1216
1217 Only local paths and ``ssh://`` URLs are supported as
1217 Only local paths and ``ssh://`` URLs are supported as
1218 destinations. For ``ssh://`` destinations, no working directory or
1218 destinations. For ``ssh://`` destinations, no working directory or
1219 ``.hg/hgrc`` will be created on the remote side.
1219 ``.hg/hgrc`` will be created on the remote side.
1220
1220
1221 To pull only a subset of changesets, specify one or more revisions
1221 To pull only a subset of changesets, specify one or more revisions
1222 identifiers with -r/--rev or branches with -b/--branch. The
1222 identifiers with -r/--rev or branches with -b/--branch. The
1223 resulting clone will contain only the specified changesets and
1223 resulting clone will contain only the specified changesets and
1224 their ancestors. These options (or 'clone src#rev dest') imply
1224 their ancestors. These options (or 'clone src#rev dest') imply
1225 --pull, even for local source repositories. Note that specifying a
1225 --pull, even for local source repositories. Note that specifying a
1226 tag will include the tagged changeset but not the changeset
1226 tag will include the tagged changeset but not the changeset
1227 containing the tag.
1227 containing the tag.
1228
1228
1229 If the source repository has a bookmark called '@' set, that
1229 If the source repository has a bookmark called '@' set, that
1230 revision will be checked out in the new repository by default.
1230 revision will be checked out in the new repository by default.
1231
1231
1232 To check out a particular version, use -u/--update, or
1232 To check out a particular version, use -u/--update, or
1233 -U/--noupdate to create a clone with no working directory.
1233 -U/--noupdate to create a clone with no working directory.
1234
1234
1235 .. container:: verbose
1235 .. container:: verbose
1236
1236
1237 For efficiency, hardlinks are used for cloning whenever the
1237 For efficiency, hardlinks are used for cloning whenever the
1238 source and destination are on the same filesystem (note this
1238 source and destination are on the same filesystem (note this
1239 applies only to the repository data, not to the working
1239 applies only to the repository data, not to the working
1240 directory). Some filesystems, such as AFS, implement hardlinking
1240 directory). Some filesystems, such as AFS, implement hardlinking
1241 incorrectly, but do not report errors. In these cases, use the
1241 incorrectly, but do not report errors. In these cases, use the
1242 --pull option to avoid hardlinking.
1242 --pull option to avoid hardlinking.
1243
1243
1244 In some cases, you can clone repositories and the working
1244 In some cases, you can clone repositories and the working
1245 directory using full hardlinks with ::
1245 directory using full hardlinks with ::
1246
1246
1247 $ cp -al REPO REPOCLONE
1247 $ cp -al REPO REPOCLONE
1248
1248
1249 This is the fastest way to clone, but it is not always safe. The
1249 This is the fastest way to clone, but it is not always safe. The
1250 operation is not atomic (making sure REPO is not modified during
1250 operation is not atomic (making sure REPO is not modified during
1251 the operation is up to you) and you have to make sure your
1251 the operation is up to you) and you have to make sure your
1252 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1252 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1253 so). Also, this is not compatible with certain extensions that
1253 so). Also, this is not compatible with certain extensions that
1254 place their metadata under the .hg directory, such as mq.
1254 place their metadata under the .hg directory, such as mq.
1255
1255
1256 Mercurial will update the working directory to the first applicable
1256 Mercurial will update the working directory to the first applicable
1257 revision from this list:
1257 revision from this list:
1258
1258
1259 a) null if -U or the source repository has no changesets
1259 a) null if -U or the source repository has no changesets
1260 b) if -u . and the source repository is local, the first parent of
1260 b) if -u . and the source repository is local, the first parent of
1261 the source repository's working directory
1261 the source repository's working directory
1262 c) the changeset specified with -u (if a branch name, this means the
1262 c) the changeset specified with -u (if a branch name, this means the
1263 latest head of that branch)
1263 latest head of that branch)
1264 d) the changeset specified with -r
1264 d) the changeset specified with -r
1265 e) the tipmost head specified with -b
1265 e) the tipmost head specified with -b
1266 f) the tipmost head specified with the url#branch source syntax
1266 f) the tipmost head specified with the url#branch source syntax
1267 g) the revision marked with the '@' bookmark, if present
1267 g) the revision marked with the '@' bookmark, if present
1268 h) the tipmost head of the default branch
1268 h) the tipmost head of the default branch
1269 i) tip
1269 i) tip
1270
1270
1271 Examples:
1271 Examples:
1272
1272
1273 - clone a remote repository to a new directory named hg/::
1273 - clone a remote repository to a new directory named hg/::
1274
1274
1275 hg clone http://selenic.com/hg
1275 hg clone http://selenic.com/hg
1276
1276
1277 - create a lightweight local clone::
1277 - create a lightweight local clone::
1278
1278
1279 hg clone project/ project-feature/
1279 hg clone project/ project-feature/
1280
1280
1281 - clone from an absolute path on an ssh server (note double-slash)::
1281 - clone from an absolute path on an ssh server (note double-slash)::
1282
1282
1283 hg clone ssh://user@server//home/projects/alpha/
1283 hg clone ssh://user@server//home/projects/alpha/
1284
1284
1285 - do a high-speed clone over a LAN while checking out a
1285 - do a high-speed clone over a LAN while checking out a
1286 specified version::
1286 specified version::
1287
1287
1288 hg clone --uncompressed http://server/repo -u 1.5
1288 hg clone --uncompressed http://server/repo -u 1.5
1289
1289
1290 - create a repository without changesets after a particular revision::
1290 - create a repository without changesets after a particular revision::
1291
1291
1292 hg clone -r 04e544 experimental/ good/
1292 hg clone -r 04e544 experimental/ good/
1293
1293
1294 - clone (and track) a particular named branch::
1294 - clone (and track) a particular named branch::
1295
1295
1296 hg clone http://selenic.com/hg#stable
1296 hg clone http://selenic.com/hg#stable
1297
1297
1298 See :hg:`help urls` for details on specifying URLs.
1298 See :hg:`help urls` for details on specifying URLs.
1299
1299
1300 Returns 0 on success.
1300 Returns 0 on success.
1301 """
1301 """
1302 if opts.get('noupdate') and opts.get('updaterev'):
1302 if opts.get('noupdate') and opts.get('updaterev'):
1303 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1303 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1304
1304
1305 r = hg.clone(ui, opts, source, dest,
1305 r = hg.clone(ui, opts, source, dest,
1306 pull=opts.get('pull'),
1306 pull=opts.get('pull'),
1307 stream=opts.get('uncompressed'),
1307 stream=opts.get('uncompressed'),
1308 rev=opts.get('rev'),
1308 rev=opts.get('rev'),
1309 update=opts.get('updaterev') or not opts.get('noupdate'),
1309 update=opts.get('updaterev') or not opts.get('noupdate'),
1310 branch=opts.get('branch'))
1310 branch=opts.get('branch'))
1311
1311
1312 return r is None
1312 return r is None
1313
1313
1314 @command('^commit|ci',
1314 @command('^commit|ci',
1315 [('A', 'addremove', None,
1315 [('A', 'addremove', None,
1316 _('mark new/missing files as added/removed before committing')),
1316 _('mark new/missing files as added/removed before committing')),
1317 ('', 'close-branch', None,
1317 ('', 'close-branch', None,
1318 _('mark a branch as closed, hiding it from the branch list')),
1318 _('mark a branch as closed, hiding it from the branch list')),
1319 ('', 'amend', None, _('amend the parent of the working dir')),
1319 ('', 'amend', None, _('amend the parent of the working dir')),
1320 ('s', 'secret', None, _('use the secret phase for committing')),
1320 ('s', 'secret', None, _('use the secret phase for committing')),
1321 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1321 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1322 _('[OPTION]... [FILE]...'))
1322 _('[OPTION]... [FILE]...'))
1323 def commit(ui, repo, *pats, **opts):
1323 def commit(ui, repo, *pats, **opts):
1324 """commit the specified files or all outstanding changes
1324 """commit the specified files or all outstanding changes
1325
1325
1326 Commit changes to the given files into the repository. Unlike a
1326 Commit changes to the given files into the repository. Unlike a
1327 centralized SCM, this operation is a local operation. See
1327 centralized SCM, this operation is a local operation. See
1328 :hg:`push` for a way to actively distribute your changes.
1328 :hg:`push` for a way to actively distribute your changes.
1329
1329
1330 If a list of files is omitted, all changes reported by :hg:`status`
1330 If a list of files is omitted, all changes reported by :hg:`status`
1331 will be committed.
1331 will be committed.
1332
1332
1333 If you are committing the result of a merge, do not provide any
1333 If you are committing the result of a merge, do not provide any
1334 filenames or -I/-X filters.
1334 filenames or -I/-X filters.
1335
1335
1336 If no commit message is specified, Mercurial starts your
1336 If no commit message is specified, Mercurial starts your
1337 configured editor where you can enter a message. In case your
1337 configured editor where you can enter a message. In case your
1338 commit fails, you will find a backup of your message in
1338 commit fails, you will find a backup of your message in
1339 ``.hg/last-message.txt``.
1339 ``.hg/last-message.txt``.
1340
1340
1341 The --amend flag can be used to amend the parent of the
1341 The --amend flag can be used to amend the parent of the
1342 working directory with a new commit that contains the changes
1342 working directory with a new commit that contains the changes
1343 in the parent in addition to those currently reported by :hg:`status`,
1343 in the parent in addition to those currently reported by :hg:`status`,
1344 if there are any. The old commit is stored in a backup bundle in
1344 if there are any. The old commit is stored in a backup bundle in
1345 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1345 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1346 on how to restore it).
1346 on how to restore it).
1347
1347
1348 Message, user and date are taken from the amended commit unless
1348 Message, user and date are taken from the amended commit unless
1349 specified. When a message isn't specified on the command line,
1349 specified. When a message isn't specified on the command line,
1350 the editor will open with the message of the amended commit.
1350 the editor will open with the message of the amended commit.
1351
1351
1352 It is not possible to amend public changesets (see :hg:`help phases`)
1352 It is not possible to amend public changesets (see :hg:`help phases`)
1353 or changesets that have children.
1353 or changesets that have children.
1354
1354
1355 See :hg:`help dates` for a list of formats valid for -d/--date.
1355 See :hg:`help dates` for a list of formats valid for -d/--date.
1356
1356
1357 Returns 0 on success, 1 if nothing changed.
1357 Returns 0 on success, 1 if nothing changed.
1358 """
1358 """
1359 if opts.get('subrepos'):
1359 if opts.get('subrepos'):
1360 if opts.get('amend'):
1360 if opts.get('amend'):
1361 raise util.Abort(_('cannot amend with --subrepos'))
1361 raise util.Abort(_('cannot amend with --subrepos'))
1362 # Let --subrepos on the command line override config setting.
1362 # Let --subrepos on the command line override config setting.
1363 ui.setconfig('ui', 'commitsubrepos', True)
1363 ui.setconfig('ui', 'commitsubrepos', True)
1364
1364
1365 # Save this for restoring it later
1365 # Save this for restoring it later
1366 oldcommitphase = ui.config('phases', 'new-commit')
1366 oldcommitphase = ui.config('phases', 'new-commit')
1367
1367
1368 cmdutil.checkunfinished(repo, commit=True)
1368 cmdutil.checkunfinished(repo, commit=True)
1369
1369
1370 branch = repo[None].branch()
1370 branch = repo[None].branch()
1371 bheads = repo.branchheads(branch)
1371 bheads = repo.branchheads(branch)
1372
1372
1373 extra = {}
1373 extra = {}
1374 if opts.get('close_branch'):
1374 if opts.get('close_branch'):
1375 extra['close'] = 1
1375 extra['close'] = 1
1376
1376
1377 if not bheads:
1377 if not bheads:
1378 raise util.Abort(_('can only close branch heads'))
1378 raise util.Abort(_('can only close branch heads'))
1379 elif opts.get('amend'):
1379 elif opts.get('amend'):
1380 if repo.parents()[0].p1().branch() != branch and \
1380 if repo.parents()[0].p1().branch() != branch and \
1381 repo.parents()[0].p2().branch() != branch:
1381 repo.parents()[0].p2().branch() != branch:
1382 raise util.Abort(_('can only close branch heads'))
1382 raise util.Abort(_('can only close branch heads'))
1383
1383
1384 if opts.get('amend'):
1384 if opts.get('amend'):
1385 if ui.configbool('ui', 'commitsubrepos'):
1385 if ui.configbool('ui', 'commitsubrepos'):
1386 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1386 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1387
1387
1388 old = repo['.']
1388 old = repo['.']
1389 if old.phase() == phases.public:
1389 if old.phase() == phases.public:
1390 raise util.Abort(_('cannot amend public changesets'))
1390 raise util.Abort(_('cannot amend public changesets'))
1391 if len(repo[None].parents()) > 1:
1391 if len(repo[None].parents()) > 1:
1392 raise util.Abort(_('cannot amend while merging'))
1392 raise util.Abort(_('cannot amend while merging'))
1393 if (not obsolete._enabled) and old.children():
1393 if (not obsolete._enabled) and old.children():
1394 raise util.Abort(_('cannot amend changeset with children'))
1394 raise util.Abort(_('cannot amend changeset with children'))
1395
1395
1396 e = cmdutil.commiteditor
1396 e = cmdutil.commiteditor
1397 if opts.get('force_editor'):
1397 if opts.get('force_editor'):
1398 e = cmdutil.commitforceeditor
1398 e = cmdutil.commitforceeditor
1399
1399
1400 # commitfunc is used only for temporary amend commit by cmdutil.amend
1400 def commitfunc(ui, repo, message, match, opts):
1401 def commitfunc(ui, repo, message, match, opts):
1401 editor = e
1402 editor = e
1402 # message contains text from -m or -l, if it's empty,
1403 # message contains text from -m or -l, if it's empty,
1403 # open the editor with the old message
1404 # open the editor with the old message
1404 if not message:
1405 if not message:
1405 message = old.description()
1406 message = old.description()
1406 editor = cmdutil.commitforceeditor
1407 editor = cmdutil.commitforceeditor
1407 try:
1408 if opts.get('secret'):
1409 ui.setconfig('phases', 'new-commit', 'secret')
1410
1411 return repo.commit(message,
1408 return repo.commit(message,
1412 opts.get('user') or old.user(),
1409 opts.get('user') or old.user(),
1413 opts.get('date') or old.date(),
1410 opts.get('date') or old.date(),
1414 match,
1411 match,
1415 editor=editor,
1412 editor=editor,
1416 extra=extra)
1413 extra=extra)
1417 finally:
1418 ui.setconfig('phases', 'new-commit', oldcommitphase)
1419
1414
1420 current = repo._bookmarkcurrent
1415 current = repo._bookmarkcurrent
1421 marks = old.bookmarks()
1416 marks = old.bookmarks()
1422 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1417 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1423 if node == old.node():
1418 if node == old.node():
1424 ui.status(_("nothing changed\n"))
1419 ui.status(_("nothing changed\n"))
1425 return 1
1420 return 1
1426 elif marks:
1421 elif marks:
1427 ui.debug('moving bookmarks %r from %s to %s\n' %
1422 ui.debug('moving bookmarks %r from %s to %s\n' %
1428 (marks, old.hex(), hex(node)))
1423 (marks, old.hex(), hex(node)))
1429 newmarks = repo._bookmarks
1424 newmarks = repo._bookmarks
1430 for bm in marks:
1425 for bm in marks:
1431 newmarks[bm] = node
1426 newmarks[bm] = node
1432 if bm == current:
1427 if bm == current:
1433 bookmarks.setcurrent(repo, bm)
1428 bookmarks.setcurrent(repo, bm)
1434 newmarks.write()
1429 newmarks.write()
1435 else:
1430 else:
1436 e = cmdutil.commiteditor
1431 e = cmdutil.commiteditor
1437 if opts.get('force_editor'):
1432 if opts.get('force_editor'):
1438 e = cmdutil.commitforceeditor
1433 e = cmdutil.commitforceeditor
1439
1434
1440 def commitfunc(ui, repo, message, match, opts):
1435 def commitfunc(ui, repo, message, match, opts):
1441 try:
1436 try:
1442 if opts.get('secret'):
1437 if opts.get('secret'):
1443 ui.setconfig('phases', 'new-commit', 'secret')
1438 ui.setconfig('phases', 'new-commit', 'secret')
1444
1439
1445 return repo.commit(message, opts.get('user'), opts.get('date'),
1440 return repo.commit(message, opts.get('user'), opts.get('date'),
1446 match, editor=e, extra=extra)
1441 match, editor=e, extra=extra)
1447 finally:
1442 finally:
1448 ui.setconfig('phases', 'new-commit', oldcommitphase)
1443 ui.setconfig('phases', 'new-commit', oldcommitphase)
1449
1444
1450
1445
1451 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1446 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1452
1447
1453 if not node:
1448 if not node:
1454 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1449 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1455 if stat[3]:
1450 if stat[3]:
1456 ui.status(_("nothing changed (%d missing files, see "
1451 ui.status(_("nothing changed (%d missing files, see "
1457 "'hg status')\n") % len(stat[3]))
1452 "'hg status')\n") % len(stat[3]))
1458 else:
1453 else:
1459 ui.status(_("nothing changed\n"))
1454 ui.status(_("nothing changed\n"))
1460 return 1
1455 return 1
1461
1456
1462 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1457 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1463
1458
1464 @command('config|showconfig|debugconfig',
1459 @command('config|showconfig|debugconfig',
1465 [('u', 'untrusted', None, _('show untrusted configuration options')),
1460 [('u', 'untrusted', None, _('show untrusted configuration options')),
1466 ('e', 'edit', None, _('start editor'))],
1461 ('e', 'edit', None, _('start editor'))],
1467 _('[-u] [NAME]...'))
1462 _('[-u] [NAME]...'))
1468 def config(ui, repo, *values, **opts):
1463 def config(ui, repo, *values, **opts):
1469 """show combined config settings from all hgrc files
1464 """show combined config settings from all hgrc files
1470
1465
1471 With no arguments, print names and values of all config items.
1466 With no arguments, print names and values of all config items.
1472
1467
1473 With one argument of the form section.name, print just the value
1468 With one argument of the form section.name, print just the value
1474 of that config item.
1469 of that config item.
1475
1470
1476 With multiple arguments, print names and values of all config
1471 With multiple arguments, print names and values of all config
1477 items with matching section names.
1472 items with matching section names.
1478
1473
1479 With --debug, the source (filename and line number) is printed
1474 With --debug, the source (filename and line number) is printed
1480 for each config item.
1475 for each config item.
1481
1476
1482 Returns 0 on success.
1477 Returns 0 on success.
1483 """
1478 """
1484
1479
1485 if opts.get('edit'):
1480 if opts.get('edit'):
1486 paths = scmutil.userrcpath()
1481 paths = scmutil.userrcpath()
1487 for f in paths:
1482 for f in paths:
1488 if os.path.exists(f):
1483 if os.path.exists(f):
1489 break
1484 break
1490 else:
1485 else:
1491 f = paths[0]
1486 f = paths[0]
1492 fp = open(f, "w")
1487 fp = open(f, "w")
1493 fp.write(
1488 fp.write(
1494 '# example config (see "hg help config" for more info)\n'
1489 '# example config (see "hg help config" for more info)\n'
1495 '\n'
1490 '\n'
1496 '[ui]\n'
1491 '[ui]\n'
1497 '# name and email, e.g.\n'
1492 '# name and email, e.g.\n'
1498 '# username = Jane Doe <jdoe@example.com>\n'
1493 '# username = Jane Doe <jdoe@example.com>\n'
1499 'username =\n'
1494 'username =\n'
1500 '\n'
1495 '\n'
1501 '[extensions]\n'
1496 '[extensions]\n'
1502 '# uncomment these lines to enable some popular extensions\n'
1497 '# uncomment these lines to enable some popular extensions\n'
1503 '# (see "hg help extensions" for more info)\n'
1498 '# (see "hg help extensions" for more info)\n'
1504 '# pager =\n'
1499 '# pager =\n'
1505 '# progress =\n'
1500 '# progress =\n'
1506 '# color =\n')
1501 '# color =\n')
1507 fp.close()
1502 fp.close()
1508
1503
1509 editor = ui.geteditor()
1504 editor = ui.geteditor()
1510 util.system("%s \"%s\"" % (editor, f),
1505 util.system("%s \"%s\"" % (editor, f),
1511 onerr=util.Abort, errprefix=_("edit failed"),
1506 onerr=util.Abort, errprefix=_("edit failed"),
1512 out=ui.fout)
1507 out=ui.fout)
1513 return
1508 return
1514
1509
1515 for f in scmutil.rcpath():
1510 for f in scmutil.rcpath():
1516 ui.debug('read config from: %s\n' % f)
1511 ui.debug('read config from: %s\n' % f)
1517 untrusted = bool(opts.get('untrusted'))
1512 untrusted = bool(opts.get('untrusted'))
1518 if values:
1513 if values:
1519 sections = [v for v in values if '.' not in v]
1514 sections = [v for v in values if '.' not in v]
1520 items = [v for v in values if '.' in v]
1515 items = [v for v in values if '.' in v]
1521 if len(items) > 1 or items and sections:
1516 if len(items) > 1 or items and sections:
1522 raise util.Abort(_('only one config item permitted'))
1517 raise util.Abort(_('only one config item permitted'))
1523 for section, name, value in ui.walkconfig(untrusted=untrusted):
1518 for section, name, value in ui.walkconfig(untrusted=untrusted):
1524 value = str(value).replace('\n', '\\n')
1519 value = str(value).replace('\n', '\\n')
1525 sectname = section + '.' + name
1520 sectname = section + '.' + name
1526 if values:
1521 if values:
1527 for v in values:
1522 for v in values:
1528 if v == section:
1523 if v == section:
1529 ui.debug('%s: ' %
1524 ui.debug('%s: ' %
1530 ui.configsource(section, name, untrusted))
1525 ui.configsource(section, name, untrusted))
1531 ui.write('%s=%s\n' % (sectname, value))
1526 ui.write('%s=%s\n' % (sectname, value))
1532 elif v == sectname:
1527 elif v == sectname:
1533 ui.debug('%s: ' %
1528 ui.debug('%s: ' %
1534 ui.configsource(section, name, untrusted))
1529 ui.configsource(section, name, untrusted))
1535 ui.write(value, '\n')
1530 ui.write(value, '\n')
1536 else:
1531 else:
1537 ui.debug('%s: ' %
1532 ui.debug('%s: ' %
1538 ui.configsource(section, name, untrusted))
1533 ui.configsource(section, name, untrusted))
1539 ui.write('%s=%s\n' % (sectname, value))
1534 ui.write('%s=%s\n' % (sectname, value))
1540
1535
1541 @command('copy|cp',
1536 @command('copy|cp',
1542 [('A', 'after', None, _('record a copy that has already occurred')),
1537 [('A', 'after', None, _('record a copy that has already occurred')),
1543 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1538 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1544 ] + walkopts + dryrunopts,
1539 ] + walkopts + dryrunopts,
1545 _('[OPTION]... [SOURCE]... DEST'))
1540 _('[OPTION]... [SOURCE]... DEST'))
1546 def copy(ui, repo, *pats, **opts):
1541 def copy(ui, repo, *pats, **opts):
1547 """mark files as copied for the next commit
1542 """mark files as copied for the next commit
1548
1543
1549 Mark dest as having copies of source files. If dest is a
1544 Mark dest as having copies of source files. If dest is a
1550 directory, copies are put in that directory. If dest is a file,
1545 directory, copies are put in that directory. If dest is a file,
1551 the source must be a single file.
1546 the source must be a single file.
1552
1547
1553 By default, this command copies the contents of files as they
1548 By default, this command copies the contents of files as they
1554 exist in the working directory. If invoked with -A/--after, the
1549 exist in the working directory. If invoked with -A/--after, the
1555 operation is recorded, but no copying is performed.
1550 operation is recorded, but no copying is performed.
1556
1551
1557 This command takes effect with the next commit. To undo a copy
1552 This command takes effect with the next commit. To undo a copy
1558 before that, see :hg:`revert`.
1553 before that, see :hg:`revert`.
1559
1554
1560 Returns 0 on success, 1 if errors are encountered.
1555 Returns 0 on success, 1 if errors are encountered.
1561 """
1556 """
1562 wlock = repo.wlock(False)
1557 wlock = repo.wlock(False)
1563 try:
1558 try:
1564 return cmdutil.copy(ui, repo, pats, opts)
1559 return cmdutil.copy(ui, repo, pats, opts)
1565 finally:
1560 finally:
1566 wlock.release()
1561 wlock.release()
1567
1562
1568 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1563 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1569 def debugancestor(ui, repo, *args):
1564 def debugancestor(ui, repo, *args):
1570 """find the ancestor revision of two revisions in a given index"""
1565 """find the ancestor revision of two revisions in a given index"""
1571 if len(args) == 3:
1566 if len(args) == 3:
1572 index, rev1, rev2 = args
1567 index, rev1, rev2 = args
1573 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1568 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1574 lookup = r.lookup
1569 lookup = r.lookup
1575 elif len(args) == 2:
1570 elif len(args) == 2:
1576 if not repo:
1571 if not repo:
1577 raise util.Abort(_("there is no Mercurial repository here "
1572 raise util.Abort(_("there is no Mercurial repository here "
1578 "(.hg not found)"))
1573 "(.hg not found)"))
1579 rev1, rev2 = args
1574 rev1, rev2 = args
1580 r = repo.changelog
1575 r = repo.changelog
1581 lookup = repo.lookup
1576 lookup = repo.lookup
1582 else:
1577 else:
1583 raise util.Abort(_('either two or three arguments required'))
1578 raise util.Abort(_('either two or three arguments required'))
1584 a = r.ancestor(lookup(rev1), lookup(rev2))
1579 a = r.ancestor(lookup(rev1), lookup(rev2))
1585 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1580 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1586
1581
1587 @command('debugbuilddag',
1582 @command('debugbuilddag',
1588 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1583 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1589 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1584 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1590 ('n', 'new-file', None, _('add new file at each rev'))],
1585 ('n', 'new-file', None, _('add new file at each rev'))],
1591 _('[OPTION]... [TEXT]'))
1586 _('[OPTION]... [TEXT]'))
1592 def debugbuilddag(ui, repo, text=None,
1587 def debugbuilddag(ui, repo, text=None,
1593 mergeable_file=False,
1588 mergeable_file=False,
1594 overwritten_file=False,
1589 overwritten_file=False,
1595 new_file=False):
1590 new_file=False):
1596 """builds a repo with a given DAG from scratch in the current empty repo
1591 """builds a repo with a given DAG from scratch in the current empty repo
1597
1592
1598 The description of the DAG is read from stdin if not given on the
1593 The description of the DAG is read from stdin if not given on the
1599 command line.
1594 command line.
1600
1595
1601 Elements:
1596 Elements:
1602
1597
1603 - "+n" is a linear run of n nodes based on the current default parent
1598 - "+n" is a linear run of n nodes based on the current default parent
1604 - "." is a single node based on the current default parent
1599 - "." is a single node based on the current default parent
1605 - "$" resets the default parent to null (implied at the start);
1600 - "$" resets the default parent to null (implied at the start);
1606 otherwise the default parent is always the last node created
1601 otherwise the default parent is always the last node created
1607 - "<p" sets the default parent to the backref p
1602 - "<p" sets the default parent to the backref p
1608 - "*p" is a fork at parent p, which is a backref
1603 - "*p" is a fork at parent p, which is a backref
1609 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1604 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1610 - "/p2" is a merge of the preceding node and p2
1605 - "/p2" is a merge of the preceding node and p2
1611 - ":tag" defines a local tag for the preceding node
1606 - ":tag" defines a local tag for the preceding node
1612 - "@branch" sets the named branch for subsequent nodes
1607 - "@branch" sets the named branch for subsequent nodes
1613 - "#...\\n" is a comment up to the end of the line
1608 - "#...\\n" is a comment up to the end of the line
1614
1609
1615 Whitespace between the above elements is ignored.
1610 Whitespace between the above elements is ignored.
1616
1611
1617 A backref is either
1612 A backref is either
1618
1613
1619 - a number n, which references the node curr-n, where curr is the current
1614 - a number n, which references the node curr-n, where curr is the current
1620 node, or
1615 node, or
1621 - the name of a local tag you placed earlier using ":tag", or
1616 - the name of a local tag you placed earlier using ":tag", or
1622 - empty to denote the default parent.
1617 - empty to denote the default parent.
1623
1618
1624 All string valued-elements are either strictly alphanumeric, or must
1619 All string valued-elements are either strictly alphanumeric, or must
1625 be enclosed in double quotes ("..."), with "\\" as escape character.
1620 be enclosed in double quotes ("..."), with "\\" as escape character.
1626 """
1621 """
1627
1622
1628 if text is None:
1623 if text is None:
1629 ui.status(_("reading DAG from stdin\n"))
1624 ui.status(_("reading DAG from stdin\n"))
1630 text = ui.fin.read()
1625 text = ui.fin.read()
1631
1626
1632 cl = repo.changelog
1627 cl = repo.changelog
1633 if len(cl) > 0:
1628 if len(cl) > 0:
1634 raise util.Abort(_('repository is not empty'))
1629 raise util.Abort(_('repository is not empty'))
1635
1630
1636 # determine number of revs in DAG
1631 # determine number of revs in DAG
1637 total = 0
1632 total = 0
1638 for type, data in dagparser.parsedag(text):
1633 for type, data in dagparser.parsedag(text):
1639 if type == 'n':
1634 if type == 'n':
1640 total += 1
1635 total += 1
1641
1636
1642 if mergeable_file:
1637 if mergeable_file:
1643 linesperrev = 2
1638 linesperrev = 2
1644 # make a file with k lines per rev
1639 # make a file with k lines per rev
1645 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1640 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1646 initialmergedlines.append("")
1641 initialmergedlines.append("")
1647
1642
1648 tags = []
1643 tags = []
1649
1644
1650 lock = tr = None
1645 lock = tr = None
1651 try:
1646 try:
1652 lock = repo.lock()
1647 lock = repo.lock()
1653 tr = repo.transaction("builddag")
1648 tr = repo.transaction("builddag")
1654
1649
1655 at = -1
1650 at = -1
1656 atbranch = 'default'
1651 atbranch = 'default'
1657 nodeids = []
1652 nodeids = []
1658 id = 0
1653 id = 0
1659 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1654 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1660 for type, data in dagparser.parsedag(text):
1655 for type, data in dagparser.parsedag(text):
1661 if type == 'n':
1656 if type == 'n':
1662 ui.note(('node %s\n' % str(data)))
1657 ui.note(('node %s\n' % str(data)))
1663 id, ps = data
1658 id, ps = data
1664
1659
1665 files = []
1660 files = []
1666 fctxs = {}
1661 fctxs = {}
1667
1662
1668 p2 = None
1663 p2 = None
1669 if mergeable_file:
1664 if mergeable_file:
1670 fn = "mf"
1665 fn = "mf"
1671 p1 = repo[ps[0]]
1666 p1 = repo[ps[0]]
1672 if len(ps) > 1:
1667 if len(ps) > 1:
1673 p2 = repo[ps[1]]
1668 p2 = repo[ps[1]]
1674 pa = p1.ancestor(p2)
1669 pa = p1.ancestor(p2)
1675 base, local, other = [x[fn].data() for x in (pa, p1,
1670 base, local, other = [x[fn].data() for x in (pa, p1,
1676 p2)]
1671 p2)]
1677 m3 = simplemerge.Merge3Text(base, local, other)
1672 m3 = simplemerge.Merge3Text(base, local, other)
1678 ml = [l.strip() for l in m3.merge_lines()]
1673 ml = [l.strip() for l in m3.merge_lines()]
1679 ml.append("")
1674 ml.append("")
1680 elif at > 0:
1675 elif at > 0:
1681 ml = p1[fn].data().split("\n")
1676 ml = p1[fn].data().split("\n")
1682 else:
1677 else:
1683 ml = initialmergedlines
1678 ml = initialmergedlines
1684 ml[id * linesperrev] += " r%i" % id
1679 ml[id * linesperrev] += " r%i" % id
1685 mergedtext = "\n".join(ml)
1680 mergedtext = "\n".join(ml)
1686 files.append(fn)
1681 files.append(fn)
1687 fctxs[fn] = context.memfilectx(fn, mergedtext)
1682 fctxs[fn] = context.memfilectx(fn, mergedtext)
1688
1683
1689 if overwritten_file:
1684 if overwritten_file:
1690 fn = "of"
1685 fn = "of"
1691 files.append(fn)
1686 files.append(fn)
1692 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1687 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1693
1688
1694 if new_file:
1689 if new_file:
1695 fn = "nf%i" % id
1690 fn = "nf%i" % id
1696 files.append(fn)
1691 files.append(fn)
1697 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1692 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1698 if len(ps) > 1:
1693 if len(ps) > 1:
1699 if not p2:
1694 if not p2:
1700 p2 = repo[ps[1]]
1695 p2 = repo[ps[1]]
1701 for fn in p2:
1696 for fn in p2:
1702 if fn.startswith("nf"):
1697 if fn.startswith("nf"):
1703 files.append(fn)
1698 files.append(fn)
1704 fctxs[fn] = p2[fn]
1699 fctxs[fn] = p2[fn]
1705
1700
1706 def fctxfn(repo, cx, path):
1701 def fctxfn(repo, cx, path):
1707 return fctxs.get(path)
1702 return fctxs.get(path)
1708
1703
1709 if len(ps) == 0 or ps[0] < 0:
1704 if len(ps) == 0 or ps[0] < 0:
1710 pars = [None, None]
1705 pars = [None, None]
1711 elif len(ps) == 1:
1706 elif len(ps) == 1:
1712 pars = [nodeids[ps[0]], None]
1707 pars = [nodeids[ps[0]], None]
1713 else:
1708 else:
1714 pars = [nodeids[p] for p in ps]
1709 pars = [nodeids[p] for p in ps]
1715 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1710 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1716 date=(id, 0),
1711 date=(id, 0),
1717 user="debugbuilddag",
1712 user="debugbuilddag",
1718 extra={'branch': atbranch})
1713 extra={'branch': atbranch})
1719 nodeid = repo.commitctx(cx)
1714 nodeid = repo.commitctx(cx)
1720 nodeids.append(nodeid)
1715 nodeids.append(nodeid)
1721 at = id
1716 at = id
1722 elif type == 'l':
1717 elif type == 'l':
1723 id, name = data
1718 id, name = data
1724 ui.note(('tag %s\n' % name))
1719 ui.note(('tag %s\n' % name))
1725 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1720 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1726 elif type == 'a':
1721 elif type == 'a':
1727 ui.note(('branch %s\n' % data))
1722 ui.note(('branch %s\n' % data))
1728 atbranch = data
1723 atbranch = data
1729 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1724 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1730 tr.close()
1725 tr.close()
1731
1726
1732 if tags:
1727 if tags:
1733 repo.opener.write("localtags", "".join(tags))
1728 repo.opener.write("localtags", "".join(tags))
1734 finally:
1729 finally:
1735 ui.progress(_('building'), None)
1730 ui.progress(_('building'), None)
1736 release(tr, lock)
1731 release(tr, lock)
1737
1732
1738 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1733 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1739 def debugbundle(ui, bundlepath, all=None, **opts):
1734 def debugbundle(ui, bundlepath, all=None, **opts):
1740 """lists the contents of a bundle"""
1735 """lists the contents of a bundle"""
1741 f = hg.openpath(ui, bundlepath)
1736 f = hg.openpath(ui, bundlepath)
1742 try:
1737 try:
1743 gen = changegroup.readbundle(f, bundlepath)
1738 gen = changegroup.readbundle(f, bundlepath)
1744 if all:
1739 if all:
1745 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1740 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1746
1741
1747 def showchunks(named):
1742 def showchunks(named):
1748 ui.write("\n%s\n" % named)
1743 ui.write("\n%s\n" % named)
1749 chain = None
1744 chain = None
1750 while True:
1745 while True:
1751 chunkdata = gen.deltachunk(chain)
1746 chunkdata = gen.deltachunk(chain)
1752 if not chunkdata:
1747 if not chunkdata:
1753 break
1748 break
1754 node = chunkdata['node']
1749 node = chunkdata['node']
1755 p1 = chunkdata['p1']
1750 p1 = chunkdata['p1']
1756 p2 = chunkdata['p2']
1751 p2 = chunkdata['p2']
1757 cs = chunkdata['cs']
1752 cs = chunkdata['cs']
1758 deltabase = chunkdata['deltabase']
1753 deltabase = chunkdata['deltabase']
1759 delta = chunkdata['delta']
1754 delta = chunkdata['delta']
1760 ui.write("%s %s %s %s %s %s\n" %
1755 ui.write("%s %s %s %s %s %s\n" %
1761 (hex(node), hex(p1), hex(p2),
1756 (hex(node), hex(p1), hex(p2),
1762 hex(cs), hex(deltabase), len(delta)))
1757 hex(cs), hex(deltabase), len(delta)))
1763 chain = node
1758 chain = node
1764
1759
1765 chunkdata = gen.changelogheader()
1760 chunkdata = gen.changelogheader()
1766 showchunks("changelog")
1761 showchunks("changelog")
1767 chunkdata = gen.manifestheader()
1762 chunkdata = gen.manifestheader()
1768 showchunks("manifest")
1763 showchunks("manifest")
1769 while True:
1764 while True:
1770 chunkdata = gen.filelogheader()
1765 chunkdata = gen.filelogheader()
1771 if not chunkdata:
1766 if not chunkdata:
1772 break
1767 break
1773 fname = chunkdata['filename']
1768 fname = chunkdata['filename']
1774 showchunks(fname)
1769 showchunks(fname)
1775 else:
1770 else:
1776 chunkdata = gen.changelogheader()
1771 chunkdata = gen.changelogheader()
1777 chain = None
1772 chain = None
1778 while True:
1773 while True:
1779 chunkdata = gen.deltachunk(chain)
1774 chunkdata = gen.deltachunk(chain)
1780 if not chunkdata:
1775 if not chunkdata:
1781 break
1776 break
1782 node = chunkdata['node']
1777 node = chunkdata['node']
1783 ui.write("%s\n" % hex(node))
1778 ui.write("%s\n" % hex(node))
1784 chain = node
1779 chain = node
1785 finally:
1780 finally:
1786 f.close()
1781 f.close()
1787
1782
1788 @command('debugcheckstate', [], '')
1783 @command('debugcheckstate', [], '')
1789 def debugcheckstate(ui, repo):
1784 def debugcheckstate(ui, repo):
1790 """validate the correctness of the current dirstate"""
1785 """validate the correctness of the current dirstate"""
1791 parent1, parent2 = repo.dirstate.parents()
1786 parent1, parent2 = repo.dirstate.parents()
1792 m1 = repo[parent1].manifest()
1787 m1 = repo[parent1].manifest()
1793 m2 = repo[parent2].manifest()
1788 m2 = repo[parent2].manifest()
1794 errors = 0
1789 errors = 0
1795 for f in repo.dirstate:
1790 for f in repo.dirstate:
1796 state = repo.dirstate[f]
1791 state = repo.dirstate[f]
1797 if state in "nr" and f not in m1:
1792 if state in "nr" and f not in m1:
1798 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1793 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1799 errors += 1
1794 errors += 1
1800 if state in "a" and f in m1:
1795 if state in "a" and f in m1:
1801 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1796 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1802 errors += 1
1797 errors += 1
1803 if state in "m" and f not in m1 and f not in m2:
1798 if state in "m" and f not in m1 and f not in m2:
1804 ui.warn(_("%s in state %s, but not in either manifest\n") %
1799 ui.warn(_("%s in state %s, but not in either manifest\n") %
1805 (f, state))
1800 (f, state))
1806 errors += 1
1801 errors += 1
1807 for f in m1:
1802 for f in m1:
1808 state = repo.dirstate[f]
1803 state = repo.dirstate[f]
1809 if state not in "nrm":
1804 if state not in "nrm":
1810 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1805 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1811 errors += 1
1806 errors += 1
1812 if errors:
1807 if errors:
1813 error = _(".hg/dirstate inconsistent with current parent's manifest")
1808 error = _(".hg/dirstate inconsistent with current parent's manifest")
1814 raise util.Abort(error)
1809 raise util.Abort(error)
1815
1810
1816 @command('debugcommands', [], _('[COMMAND]'))
1811 @command('debugcommands', [], _('[COMMAND]'))
1817 def debugcommands(ui, cmd='', *args):
1812 def debugcommands(ui, cmd='', *args):
1818 """list all available commands and options"""
1813 """list all available commands and options"""
1819 for cmd, vals in sorted(table.iteritems()):
1814 for cmd, vals in sorted(table.iteritems()):
1820 cmd = cmd.split('|')[0].strip('^')
1815 cmd = cmd.split('|')[0].strip('^')
1821 opts = ', '.join([i[1] for i in vals[1]])
1816 opts = ', '.join([i[1] for i in vals[1]])
1822 ui.write('%s: %s\n' % (cmd, opts))
1817 ui.write('%s: %s\n' % (cmd, opts))
1823
1818
1824 @command('debugcomplete',
1819 @command('debugcomplete',
1825 [('o', 'options', None, _('show the command options'))],
1820 [('o', 'options', None, _('show the command options'))],
1826 _('[-o] CMD'))
1821 _('[-o] CMD'))
1827 def debugcomplete(ui, cmd='', **opts):
1822 def debugcomplete(ui, cmd='', **opts):
1828 """returns the completion list associated with the given command"""
1823 """returns the completion list associated with the given command"""
1829
1824
1830 if opts.get('options'):
1825 if opts.get('options'):
1831 options = []
1826 options = []
1832 otables = [globalopts]
1827 otables = [globalopts]
1833 if cmd:
1828 if cmd:
1834 aliases, entry = cmdutil.findcmd(cmd, table, False)
1829 aliases, entry = cmdutil.findcmd(cmd, table, False)
1835 otables.append(entry[1])
1830 otables.append(entry[1])
1836 for t in otables:
1831 for t in otables:
1837 for o in t:
1832 for o in t:
1838 if "(DEPRECATED)" in o[3]:
1833 if "(DEPRECATED)" in o[3]:
1839 continue
1834 continue
1840 if o[0]:
1835 if o[0]:
1841 options.append('-%s' % o[0])
1836 options.append('-%s' % o[0])
1842 options.append('--%s' % o[1])
1837 options.append('--%s' % o[1])
1843 ui.write("%s\n" % "\n".join(options))
1838 ui.write("%s\n" % "\n".join(options))
1844 return
1839 return
1845
1840
1846 cmdlist = cmdutil.findpossible(cmd, table)
1841 cmdlist = cmdutil.findpossible(cmd, table)
1847 if ui.verbose:
1842 if ui.verbose:
1848 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1843 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1849 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1844 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1850
1845
1851 @command('debugdag',
1846 @command('debugdag',
1852 [('t', 'tags', None, _('use tags as labels')),
1847 [('t', 'tags', None, _('use tags as labels')),
1853 ('b', 'branches', None, _('annotate with branch names')),
1848 ('b', 'branches', None, _('annotate with branch names')),
1854 ('', 'dots', None, _('use dots for runs')),
1849 ('', 'dots', None, _('use dots for runs')),
1855 ('s', 'spaces', None, _('separate elements by spaces'))],
1850 ('s', 'spaces', None, _('separate elements by spaces'))],
1856 _('[OPTION]... [FILE [REV]...]'))
1851 _('[OPTION]... [FILE [REV]...]'))
1857 def debugdag(ui, repo, file_=None, *revs, **opts):
1852 def debugdag(ui, repo, file_=None, *revs, **opts):
1858 """format the changelog or an index DAG as a concise textual description
1853 """format the changelog or an index DAG as a concise textual description
1859
1854
1860 If you pass a revlog index, the revlog's DAG is emitted. If you list
1855 If you pass a revlog index, the revlog's DAG is emitted. If you list
1861 revision numbers, they get labeled in the output as rN.
1856 revision numbers, they get labeled in the output as rN.
1862
1857
1863 Otherwise, the changelog DAG of the current repo is emitted.
1858 Otherwise, the changelog DAG of the current repo is emitted.
1864 """
1859 """
1865 spaces = opts.get('spaces')
1860 spaces = opts.get('spaces')
1866 dots = opts.get('dots')
1861 dots = opts.get('dots')
1867 if file_:
1862 if file_:
1868 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1863 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1869 revs = set((int(r) for r in revs))
1864 revs = set((int(r) for r in revs))
1870 def events():
1865 def events():
1871 for r in rlog:
1866 for r in rlog:
1872 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1867 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1873 if p != -1)))
1868 if p != -1)))
1874 if r in revs:
1869 if r in revs:
1875 yield 'l', (r, "r%i" % r)
1870 yield 'l', (r, "r%i" % r)
1876 elif repo:
1871 elif repo:
1877 cl = repo.changelog
1872 cl = repo.changelog
1878 tags = opts.get('tags')
1873 tags = opts.get('tags')
1879 branches = opts.get('branches')
1874 branches = opts.get('branches')
1880 if tags:
1875 if tags:
1881 labels = {}
1876 labels = {}
1882 for l, n in repo.tags().items():
1877 for l, n in repo.tags().items():
1883 labels.setdefault(cl.rev(n), []).append(l)
1878 labels.setdefault(cl.rev(n), []).append(l)
1884 def events():
1879 def events():
1885 b = "default"
1880 b = "default"
1886 for r in cl:
1881 for r in cl:
1887 if branches:
1882 if branches:
1888 newb = cl.read(cl.node(r))[5]['branch']
1883 newb = cl.read(cl.node(r))[5]['branch']
1889 if newb != b:
1884 if newb != b:
1890 yield 'a', newb
1885 yield 'a', newb
1891 b = newb
1886 b = newb
1892 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1887 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1893 if p != -1)))
1888 if p != -1)))
1894 if tags:
1889 if tags:
1895 ls = labels.get(r)
1890 ls = labels.get(r)
1896 if ls:
1891 if ls:
1897 for l in ls:
1892 for l in ls:
1898 yield 'l', (r, l)
1893 yield 'l', (r, l)
1899 else:
1894 else:
1900 raise util.Abort(_('need repo for changelog dag'))
1895 raise util.Abort(_('need repo for changelog dag'))
1901
1896
1902 for line in dagparser.dagtextlines(events(),
1897 for line in dagparser.dagtextlines(events(),
1903 addspaces=spaces,
1898 addspaces=spaces,
1904 wraplabels=True,
1899 wraplabels=True,
1905 wrapannotations=True,
1900 wrapannotations=True,
1906 wrapnonlinear=dots,
1901 wrapnonlinear=dots,
1907 usedots=dots,
1902 usedots=dots,
1908 maxlinewidth=70):
1903 maxlinewidth=70):
1909 ui.write(line)
1904 ui.write(line)
1910 ui.write("\n")
1905 ui.write("\n")
1911
1906
1912 @command('debugdata',
1907 @command('debugdata',
1913 [('c', 'changelog', False, _('open changelog')),
1908 [('c', 'changelog', False, _('open changelog')),
1914 ('m', 'manifest', False, _('open manifest'))],
1909 ('m', 'manifest', False, _('open manifest'))],
1915 _('-c|-m|FILE REV'))
1910 _('-c|-m|FILE REV'))
1916 def debugdata(ui, repo, file_, rev=None, **opts):
1911 def debugdata(ui, repo, file_, rev=None, **opts):
1917 """dump the contents of a data file revision"""
1912 """dump the contents of a data file revision"""
1918 if opts.get('changelog') or opts.get('manifest'):
1913 if opts.get('changelog') or opts.get('manifest'):
1919 file_, rev = None, file_
1914 file_, rev = None, file_
1920 elif rev is None:
1915 elif rev is None:
1921 raise error.CommandError('debugdata', _('invalid arguments'))
1916 raise error.CommandError('debugdata', _('invalid arguments'))
1922 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1917 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1923 try:
1918 try:
1924 ui.write(r.revision(r.lookup(rev)))
1919 ui.write(r.revision(r.lookup(rev)))
1925 except KeyError:
1920 except KeyError:
1926 raise util.Abort(_('invalid revision identifier %s') % rev)
1921 raise util.Abort(_('invalid revision identifier %s') % rev)
1927
1922
1928 @command('debugdate',
1923 @command('debugdate',
1929 [('e', 'extended', None, _('try extended date formats'))],
1924 [('e', 'extended', None, _('try extended date formats'))],
1930 _('[-e] DATE [RANGE]'))
1925 _('[-e] DATE [RANGE]'))
1931 def debugdate(ui, date, range=None, **opts):
1926 def debugdate(ui, date, range=None, **opts):
1932 """parse and display a date"""
1927 """parse and display a date"""
1933 if opts["extended"]:
1928 if opts["extended"]:
1934 d = util.parsedate(date, util.extendeddateformats)
1929 d = util.parsedate(date, util.extendeddateformats)
1935 else:
1930 else:
1936 d = util.parsedate(date)
1931 d = util.parsedate(date)
1937 ui.write(("internal: %s %s\n") % d)
1932 ui.write(("internal: %s %s\n") % d)
1938 ui.write(("standard: %s\n") % util.datestr(d))
1933 ui.write(("standard: %s\n") % util.datestr(d))
1939 if range:
1934 if range:
1940 m = util.matchdate(range)
1935 m = util.matchdate(range)
1941 ui.write(("match: %s\n") % m(d[0]))
1936 ui.write(("match: %s\n") % m(d[0]))
1942
1937
1943 @command('debugdiscovery',
1938 @command('debugdiscovery',
1944 [('', 'old', None, _('use old-style discovery')),
1939 [('', 'old', None, _('use old-style discovery')),
1945 ('', 'nonheads', None,
1940 ('', 'nonheads', None,
1946 _('use old-style discovery with non-heads included')),
1941 _('use old-style discovery with non-heads included')),
1947 ] + remoteopts,
1942 ] + remoteopts,
1948 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1943 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1949 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1944 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1950 """runs the changeset discovery protocol in isolation"""
1945 """runs the changeset discovery protocol in isolation"""
1951 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1946 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1952 opts.get('branch'))
1947 opts.get('branch'))
1953 remote = hg.peer(repo, opts, remoteurl)
1948 remote = hg.peer(repo, opts, remoteurl)
1954 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1949 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1955
1950
1956 # make sure tests are repeatable
1951 # make sure tests are repeatable
1957 random.seed(12323)
1952 random.seed(12323)
1958
1953
1959 def doit(localheads, remoteheads, remote=remote):
1954 def doit(localheads, remoteheads, remote=remote):
1960 if opts.get('old'):
1955 if opts.get('old'):
1961 if localheads:
1956 if localheads:
1962 raise util.Abort('cannot use localheads with old style '
1957 raise util.Abort('cannot use localheads with old style '
1963 'discovery')
1958 'discovery')
1964 if not util.safehasattr(remote, 'branches'):
1959 if not util.safehasattr(remote, 'branches'):
1965 # enable in-client legacy support
1960 # enable in-client legacy support
1966 remote = localrepo.locallegacypeer(remote.local())
1961 remote = localrepo.locallegacypeer(remote.local())
1967 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1962 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1968 force=True)
1963 force=True)
1969 common = set(common)
1964 common = set(common)
1970 if not opts.get('nonheads'):
1965 if not opts.get('nonheads'):
1971 ui.write(("unpruned common: %s\n") %
1966 ui.write(("unpruned common: %s\n") %
1972 " ".join(sorted(short(n) for n in common)))
1967 " ".join(sorted(short(n) for n in common)))
1973 dag = dagutil.revlogdag(repo.changelog)
1968 dag = dagutil.revlogdag(repo.changelog)
1974 all = dag.ancestorset(dag.internalizeall(common))
1969 all = dag.ancestorset(dag.internalizeall(common))
1975 common = dag.externalizeall(dag.headsetofconnecteds(all))
1970 common = dag.externalizeall(dag.headsetofconnecteds(all))
1976 else:
1971 else:
1977 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1972 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1978 common = set(common)
1973 common = set(common)
1979 rheads = set(hds)
1974 rheads = set(hds)
1980 lheads = set(repo.heads())
1975 lheads = set(repo.heads())
1981 ui.write(("common heads: %s\n") %
1976 ui.write(("common heads: %s\n") %
1982 " ".join(sorted(short(n) for n in common)))
1977 " ".join(sorted(short(n) for n in common)))
1983 if lheads <= common:
1978 if lheads <= common:
1984 ui.write(("local is subset\n"))
1979 ui.write(("local is subset\n"))
1985 elif rheads <= common:
1980 elif rheads <= common:
1986 ui.write(("remote is subset\n"))
1981 ui.write(("remote is subset\n"))
1987
1982
1988 serverlogs = opts.get('serverlog')
1983 serverlogs = opts.get('serverlog')
1989 if serverlogs:
1984 if serverlogs:
1990 for filename in serverlogs:
1985 for filename in serverlogs:
1991 logfile = open(filename, 'r')
1986 logfile = open(filename, 'r')
1992 try:
1987 try:
1993 line = logfile.readline()
1988 line = logfile.readline()
1994 while line:
1989 while line:
1995 parts = line.strip().split(';')
1990 parts = line.strip().split(';')
1996 op = parts[1]
1991 op = parts[1]
1997 if op == 'cg':
1992 if op == 'cg':
1998 pass
1993 pass
1999 elif op == 'cgss':
1994 elif op == 'cgss':
2000 doit(parts[2].split(' '), parts[3].split(' '))
1995 doit(parts[2].split(' '), parts[3].split(' '))
2001 elif op == 'unb':
1996 elif op == 'unb':
2002 doit(parts[3].split(' '), parts[2].split(' '))
1997 doit(parts[3].split(' '), parts[2].split(' '))
2003 line = logfile.readline()
1998 line = logfile.readline()
2004 finally:
1999 finally:
2005 logfile.close()
2000 logfile.close()
2006
2001
2007 else:
2002 else:
2008 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2003 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2009 opts.get('remote_head'))
2004 opts.get('remote_head'))
2010 localrevs = opts.get('local_head')
2005 localrevs = opts.get('local_head')
2011 doit(localrevs, remoterevs)
2006 doit(localrevs, remoterevs)
2012
2007
2013 @command('debugfileset',
2008 @command('debugfileset',
2014 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2009 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2015 _('[-r REV] FILESPEC'))
2010 _('[-r REV] FILESPEC'))
2016 def debugfileset(ui, repo, expr, **opts):
2011 def debugfileset(ui, repo, expr, **opts):
2017 '''parse and apply a fileset specification'''
2012 '''parse and apply a fileset specification'''
2018 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2013 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2019 if ui.verbose:
2014 if ui.verbose:
2020 tree = fileset.parse(expr)[0]
2015 tree = fileset.parse(expr)[0]
2021 ui.note(tree, "\n")
2016 ui.note(tree, "\n")
2022
2017
2023 for f in ctx.getfileset(expr):
2018 for f in ctx.getfileset(expr):
2024 ui.write("%s\n" % f)
2019 ui.write("%s\n" % f)
2025
2020
2026 @command('debugfsinfo', [], _('[PATH]'))
2021 @command('debugfsinfo', [], _('[PATH]'))
2027 def debugfsinfo(ui, path="."):
2022 def debugfsinfo(ui, path="."):
2028 """show information detected about current filesystem"""
2023 """show information detected about current filesystem"""
2029 util.writefile('.debugfsinfo', '')
2024 util.writefile('.debugfsinfo', '')
2030 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2025 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2031 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2026 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2032 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2027 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2033 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2028 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2034 and 'yes' or 'no'))
2029 and 'yes' or 'no'))
2035 os.unlink('.debugfsinfo')
2030 os.unlink('.debugfsinfo')
2036
2031
2037 @command('debuggetbundle',
2032 @command('debuggetbundle',
2038 [('H', 'head', [], _('id of head node'), _('ID')),
2033 [('H', 'head', [], _('id of head node'), _('ID')),
2039 ('C', 'common', [], _('id of common node'), _('ID')),
2034 ('C', 'common', [], _('id of common node'), _('ID')),
2040 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2035 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2041 _('REPO FILE [-H|-C ID]...'))
2036 _('REPO FILE [-H|-C ID]...'))
2042 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2037 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2043 """retrieves a bundle from a repo
2038 """retrieves a bundle from a repo
2044
2039
2045 Every ID must be a full-length hex node id string. Saves the bundle to the
2040 Every ID must be a full-length hex node id string. Saves the bundle to the
2046 given file.
2041 given file.
2047 """
2042 """
2048 repo = hg.peer(ui, opts, repopath)
2043 repo = hg.peer(ui, opts, repopath)
2049 if not repo.capable('getbundle'):
2044 if not repo.capable('getbundle'):
2050 raise util.Abort("getbundle() not supported by target repository")
2045 raise util.Abort("getbundle() not supported by target repository")
2051 args = {}
2046 args = {}
2052 if common:
2047 if common:
2053 args['common'] = [bin(s) for s in common]
2048 args['common'] = [bin(s) for s in common]
2054 if head:
2049 if head:
2055 args['heads'] = [bin(s) for s in head]
2050 args['heads'] = [bin(s) for s in head]
2056 # TODO: get desired bundlecaps from command line.
2051 # TODO: get desired bundlecaps from command line.
2057 args['bundlecaps'] = None
2052 args['bundlecaps'] = None
2058 bundle = repo.getbundle('debug', **args)
2053 bundle = repo.getbundle('debug', **args)
2059
2054
2060 bundletype = opts.get('type', 'bzip2').lower()
2055 bundletype = opts.get('type', 'bzip2').lower()
2061 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
2056 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
2062 bundletype = btypes.get(bundletype)
2057 bundletype = btypes.get(bundletype)
2063 if bundletype not in changegroup.bundletypes:
2058 if bundletype not in changegroup.bundletypes:
2064 raise util.Abort(_('unknown bundle type specified with --type'))
2059 raise util.Abort(_('unknown bundle type specified with --type'))
2065 changegroup.writebundle(bundle, bundlepath, bundletype)
2060 changegroup.writebundle(bundle, bundlepath, bundletype)
2066
2061
2067 @command('debugignore', [], '')
2062 @command('debugignore', [], '')
2068 def debugignore(ui, repo, *values, **opts):
2063 def debugignore(ui, repo, *values, **opts):
2069 """display the combined ignore pattern"""
2064 """display the combined ignore pattern"""
2070 ignore = repo.dirstate._ignore
2065 ignore = repo.dirstate._ignore
2071 includepat = getattr(ignore, 'includepat', None)
2066 includepat = getattr(ignore, 'includepat', None)
2072 if includepat is not None:
2067 if includepat is not None:
2073 ui.write("%s\n" % includepat)
2068 ui.write("%s\n" % includepat)
2074 else:
2069 else:
2075 raise util.Abort(_("no ignore patterns found"))
2070 raise util.Abort(_("no ignore patterns found"))
2076
2071
2077 @command('debugindex',
2072 @command('debugindex',
2078 [('c', 'changelog', False, _('open changelog')),
2073 [('c', 'changelog', False, _('open changelog')),
2079 ('m', 'manifest', False, _('open manifest')),
2074 ('m', 'manifest', False, _('open manifest')),
2080 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2075 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2081 _('[-f FORMAT] -c|-m|FILE'))
2076 _('[-f FORMAT] -c|-m|FILE'))
2082 def debugindex(ui, repo, file_=None, **opts):
2077 def debugindex(ui, repo, file_=None, **opts):
2083 """dump the contents of an index file"""
2078 """dump the contents of an index file"""
2084 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2079 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2085 format = opts.get('format', 0)
2080 format = opts.get('format', 0)
2086 if format not in (0, 1):
2081 if format not in (0, 1):
2087 raise util.Abort(_("unknown format %d") % format)
2082 raise util.Abort(_("unknown format %d") % format)
2088
2083
2089 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2084 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2090 if generaldelta:
2085 if generaldelta:
2091 basehdr = ' delta'
2086 basehdr = ' delta'
2092 else:
2087 else:
2093 basehdr = ' base'
2088 basehdr = ' base'
2094
2089
2095 if format == 0:
2090 if format == 0:
2096 ui.write(" rev offset length " + basehdr + " linkrev"
2091 ui.write(" rev offset length " + basehdr + " linkrev"
2097 " nodeid p1 p2\n")
2092 " nodeid p1 p2\n")
2098 elif format == 1:
2093 elif format == 1:
2099 ui.write(" rev flag offset length"
2094 ui.write(" rev flag offset length"
2100 " size " + basehdr + " link p1 p2"
2095 " size " + basehdr + " link p1 p2"
2101 " nodeid\n")
2096 " nodeid\n")
2102
2097
2103 for i in r:
2098 for i in r:
2104 node = r.node(i)
2099 node = r.node(i)
2105 if generaldelta:
2100 if generaldelta:
2106 base = r.deltaparent(i)
2101 base = r.deltaparent(i)
2107 else:
2102 else:
2108 base = r.chainbase(i)
2103 base = r.chainbase(i)
2109 if format == 0:
2104 if format == 0:
2110 try:
2105 try:
2111 pp = r.parents(node)
2106 pp = r.parents(node)
2112 except Exception:
2107 except Exception:
2113 pp = [nullid, nullid]
2108 pp = [nullid, nullid]
2114 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2109 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2115 i, r.start(i), r.length(i), base, r.linkrev(i),
2110 i, r.start(i), r.length(i), base, r.linkrev(i),
2116 short(node), short(pp[0]), short(pp[1])))
2111 short(node), short(pp[0]), short(pp[1])))
2117 elif format == 1:
2112 elif format == 1:
2118 pr = r.parentrevs(i)
2113 pr = r.parentrevs(i)
2119 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2114 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2120 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2115 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2121 base, r.linkrev(i), pr[0], pr[1], short(node)))
2116 base, r.linkrev(i), pr[0], pr[1], short(node)))
2122
2117
2123 @command('debugindexdot', [], _('FILE'))
2118 @command('debugindexdot', [], _('FILE'))
2124 def debugindexdot(ui, repo, file_):
2119 def debugindexdot(ui, repo, file_):
2125 """dump an index DAG as a graphviz dot file"""
2120 """dump an index DAG as a graphviz dot file"""
2126 r = None
2121 r = None
2127 if repo:
2122 if repo:
2128 filelog = repo.file(file_)
2123 filelog = repo.file(file_)
2129 if len(filelog):
2124 if len(filelog):
2130 r = filelog
2125 r = filelog
2131 if not r:
2126 if not r:
2132 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2127 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2133 ui.write(("digraph G {\n"))
2128 ui.write(("digraph G {\n"))
2134 for i in r:
2129 for i in r:
2135 node = r.node(i)
2130 node = r.node(i)
2136 pp = r.parents(node)
2131 pp = r.parents(node)
2137 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2132 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2138 if pp[1] != nullid:
2133 if pp[1] != nullid:
2139 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2134 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2140 ui.write("}\n")
2135 ui.write("}\n")
2141
2136
2142 @command('debuginstall', [], '')
2137 @command('debuginstall', [], '')
2143 def debuginstall(ui):
2138 def debuginstall(ui):
2144 '''test Mercurial installation
2139 '''test Mercurial installation
2145
2140
2146 Returns 0 on success.
2141 Returns 0 on success.
2147 '''
2142 '''
2148
2143
2149 def writetemp(contents):
2144 def writetemp(contents):
2150 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2145 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2151 f = os.fdopen(fd, "wb")
2146 f = os.fdopen(fd, "wb")
2152 f.write(contents)
2147 f.write(contents)
2153 f.close()
2148 f.close()
2154 return name
2149 return name
2155
2150
2156 problems = 0
2151 problems = 0
2157
2152
2158 # encoding
2153 # encoding
2159 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2154 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2160 try:
2155 try:
2161 encoding.fromlocal("test")
2156 encoding.fromlocal("test")
2162 except util.Abort, inst:
2157 except util.Abort, inst:
2163 ui.write(" %s\n" % inst)
2158 ui.write(" %s\n" % inst)
2164 ui.write(_(" (check that your locale is properly set)\n"))
2159 ui.write(_(" (check that your locale is properly set)\n"))
2165 problems += 1
2160 problems += 1
2166
2161
2167 # Python lib
2162 # Python lib
2168 ui.status(_("checking Python lib (%s)...\n")
2163 ui.status(_("checking Python lib (%s)...\n")
2169 % os.path.dirname(os.__file__))
2164 % os.path.dirname(os.__file__))
2170
2165
2171 # compiled modules
2166 # compiled modules
2172 ui.status(_("checking installed modules (%s)...\n")
2167 ui.status(_("checking installed modules (%s)...\n")
2173 % os.path.dirname(__file__))
2168 % os.path.dirname(__file__))
2174 try:
2169 try:
2175 import bdiff, mpatch, base85, osutil
2170 import bdiff, mpatch, base85, osutil
2176 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2171 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2177 except Exception, inst:
2172 except Exception, inst:
2178 ui.write(" %s\n" % inst)
2173 ui.write(" %s\n" % inst)
2179 ui.write(_(" One or more extensions could not be found"))
2174 ui.write(_(" One or more extensions could not be found"))
2180 ui.write(_(" (check that you compiled the extensions)\n"))
2175 ui.write(_(" (check that you compiled the extensions)\n"))
2181 problems += 1
2176 problems += 1
2182
2177
2183 # templates
2178 # templates
2184 import templater
2179 import templater
2185 p = templater.templatepath()
2180 p = templater.templatepath()
2186 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2181 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2187 if p:
2182 if p:
2188 m = templater.templatepath("map-cmdline.default")
2183 m = templater.templatepath("map-cmdline.default")
2189 if m:
2184 if m:
2190 # template found, check if it is working
2185 # template found, check if it is working
2191 try:
2186 try:
2192 templater.templater(m)
2187 templater.templater(m)
2193 except Exception, inst:
2188 except Exception, inst:
2194 ui.write(" %s\n" % inst)
2189 ui.write(" %s\n" % inst)
2195 p = None
2190 p = None
2196 else:
2191 else:
2197 ui.write(_(" template 'default' not found\n"))
2192 ui.write(_(" template 'default' not found\n"))
2198 p = None
2193 p = None
2199 else:
2194 else:
2200 ui.write(_(" no template directories found\n"))
2195 ui.write(_(" no template directories found\n"))
2201 if not p:
2196 if not p:
2202 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2197 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2203 problems += 1
2198 problems += 1
2204
2199
2205 # editor
2200 # editor
2206 ui.status(_("checking commit editor...\n"))
2201 ui.status(_("checking commit editor...\n"))
2207 editor = ui.geteditor()
2202 editor = ui.geteditor()
2208 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2203 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2209 if not cmdpath:
2204 if not cmdpath:
2210 if editor == 'vi':
2205 if editor == 'vi':
2211 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2206 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2212 ui.write(_(" (specify a commit editor in your configuration"
2207 ui.write(_(" (specify a commit editor in your configuration"
2213 " file)\n"))
2208 " file)\n"))
2214 else:
2209 else:
2215 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2210 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2216 ui.write(_(" (specify a commit editor in your configuration"
2211 ui.write(_(" (specify a commit editor in your configuration"
2217 " file)\n"))
2212 " file)\n"))
2218 problems += 1
2213 problems += 1
2219
2214
2220 # check username
2215 # check username
2221 ui.status(_("checking username...\n"))
2216 ui.status(_("checking username...\n"))
2222 try:
2217 try:
2223 ui.username()
2218 ui.username()
2224 except util.Abort, e:
2219 except util.Abort, e:
2225 ui.write(" %s\n" % e)
2220 ui.write(" %s\n" % e)
2226 ui.write(_(" (specify a username in your configuration file)\n"))
2221 ui.write(_(" (specify a username in your configuration file)\n"))
2227 problems += 1
2222 problems += 1
2228
2223
2229 if not problems:
2224 if not problems:
2230 ui.status(_("no problems detected\n"))
2225 ui.status(_("no problems detected\n"))
2231 else:
2226 else:
2232 ui.write(_("%s problems detected,"
2227 ui.write(_("%s problems detected,"
2233 " please check your install!\n") % problems)
2228 " please check your install!\n") % problems)
2234
2229
2235 return problems
2230 return problems
2236
2231
2237 @command('debugknown', [], _('REPO ID...'))
2232 @command('debugknown', [], _('REPO ID...'))
2238 def debugknown(ui, repopath, *ids, **opts):
2233 def debugknown(ui, repopath, *ids, **opts):
2239 """test whether node ids are known to a repo
2234 """test whether node ids are known to a repo
2240
2235
2241 Every ID must be a full-length hex node id string. Returns a list of 0s
2236 Every ID must be a full-length hex node id string. Returns a list of 0s
2242 and 1s indicating unknown/known.
2237 and 1s indicating unknown/known.
2243 """
2238 """
2244 repo = hg.peer(ui, opts, repopath)
2239 repo = hg.peer(ui, opts, repopath)
2245 if not repo.capable('known'):
2240 if not repo.capable('known'):
2246 raise util.Abort("known() not supported by target repository")
2241 raise util.Abort("known() not supported by target repository")
2247 flags = repo.known([bin(s) for s in ids])
2242 flags = repo.known([bin(s) for s in ids])
2248 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2243 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2249
2244
2250 @command('debuglabelcomplete', [], _('LABEL...'))
2245 @command('debuglabelcomplete', [], _('LABEL...'))
2251 def debuglabelcomplete(ui, repo, *args):
2246 def debuglabelcomplete(ui, repo, *args):
2252 '''complete "labels" - tags, open branch names, bookmark names'''
2247 '''complete "labels" - tags, open branch names, bookmark names'''
2253
2248
2254 labels = set()
2249 labels = set()
2255 labels.update(t[0] for t in repo.tagslist())
2250 labels.update(t[0] for t in repo.tagslist())
2256 labels.update(repo._bookmarks.keys())
2251 labels.update(repo._bookmarks.keys())
2257 labels.update(tag for (tag, heads, tip, closed)
2252 labels.update(tag for (tag, heads, tip, closed)
2258 in repo.branchmap().iterbranches() if not closed)
2253 in repo.branchmap().iterbranches() if not closed)
2259 completions = set()
2254 completions = set()
2260 if not args:
2255 if not args:
2261 args = ['']
2256 args = ['']
2262 for a in args:
2257 for a in args:
2263 completions.update(l for l in labels if l.startswith(a))
2258 completions.update(l for l in labels if l.startswith(a))
2264 ui.write('\n'.join(sorted(completions)))
2259 ui.write('\n'.join(sorted(completions)))
2265 ui.write('\n')
2260 ui.write('\n')
2266
2261
2267 @command('debugobsolete',
2262 @command('debugobsolete',
2268 [('', 'flags', 0, _('markers flag')),
2263 [('', 'flags', 0, _('markers flag')),
2269 ] + commitopts2,
2264 ] + commitopts2,
2270 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2265 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2271 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2266 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2272 """create arbitrary obsolete marker
2267 """create arbitrary obsolete marker
2273
2268
2274 With no arguments, displays the list of obsolescence markers."""
2269 With no arguments, displays the list of obsolescence markers."""
2275 def parsenodeid(s):
2270 def parsenodeid(s):
2276 try:
2271 try:
2277 # We do not use revsingle/revrange functions here to accept
2272 # We do not use revsingle/revrange functions here to accept
2278 # arbitrary node identifiers, possibly not present in the
2273 # arbitrary node identifiers, possibly not present in the
2279 # local repository.
2274 # local repository.
2280 n = bin(s)
2275 n = bin(s)
2281 if len(n) != len(nullid):
2276 if len(n) != len(nullid):
2282 raise TypeError()
2277 raise TypeError()
2283 return n
2278 return n
2284 except TypeError:
2279 except TypeError:
2285 raise util.Abort('changeset references must be full hexadecimal '
2280 raise util.Abort('changeset references must be full hexadecimal '
2286 'node identifiers')
2281 'node identifiers')
2287
2282
2288 if precursor is not None:
2283 if precursor is not None:
2289 metadata = {}
2284 metadata = {}
2290 if 'date' in opts:
2285 if 'date' in opts:
2291 metadata['date'] = opts['date']
2286 metadata['date'] = opts['date']
2292 metadata['user'] = opts['user'] or ui.username()
2287 metadata['user'] = opts['user'] or ui.username()
2293 succs = tuple(parsenodeid(succ) for succ in successors)
2288 succs = tuple(parsenodeid(succ) for succ in successors)
2294 l = repo.lock()
2289 l = repo.lock()
2295 try:
2290 try:
2296 tr = repo.transaction('debugobsolete')
2291 tr = repo.transaction('debugobsolete')
2297 try:
2292 try:
2298 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2293 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2299 opts['flags'], metadata)
2294 opts['flags'], metadata)
2300 tr.close()
2295 tr.close()
2301 finally:
2296 finally:
2302 tr.release()
2297 tr.release()
2303 finally:
2298 finally:
2304 l.release()
2299 l.release()
2305 else:
2300 else:
2306 for m in obsolete.allmarkers(repo):
2301 for m in obsolete.allmarkers(repo):
2307 cmdutil.showmarker(ui, m)
2302 cmdutil.showmarker(ui, m)
2308
2303
2309 @command('debugpathcomplete',
2304 @command('debugpathcomplete',
2310 [('f', 'full', None, _('complete an entire path')),
2305 [('f', 'full', None, _('complete an entire path')),
2311 ('n', 'normal', None, _('show only normal files')),
2306 ('n', 'normal', None, _('show only normal files')),
2312 ('a', 'added', None, _('show only added files')),
2307 ('a', 'added', None, _('show only added files')),
2313 ('r', 'removed', None, _('show only removed files'))],
2308 ('r', 'removed', None, _('show only removed files'))],
2314 _('FILESPEC...'))
2309 _('FILESPEC...'))
2315 def debugpathcomplete(ui, repo, *specs, **opts):
2310 def debugpathcomplete(ui, repo, *specs, **opts):
2316 '''complete part or all of a tracked path
2311 '''complete part or all of a tracked path
2317
2312
2318 This command supports shells that offer path name completion. It
2313 This command supports shells that offer path name completion. It
2319 currently completes only files already known to the dirstate.
2314 currently completes only files already known to the dirstate.
2320
2315
2321 Completion extends only to the next path segment unless
2316 Completion extends only to the next path segment unless
2322 --full is specified, in which case entire paths are used.'''
2317 --full is specified, in which case entire paths are used.'''
2323
2318
2324 def complete(path, acceptable):
2319 def complete(path, acceptable):
2325 dirstate = repo.dirstate
2320 dirstate = repo.dirstate
2326 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2321 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2327 rootdir = repo.root + os.sep
2322 rootdir = repo.root + os.sep
2328 if spec != repo.root and not spec.startswith(rootdir):
2323 if spec != repo.root and not spec.startswith(rootdir):
2329 return [], []
2324 return [], []
2330 if os.path.isdir(spec):
2325 if os.path.isdir(spec):
2331 spec += '/'
2326 spec += '/'
2332 spec = spec[len(rootdir):]
2327 spec = spec[len(rootdir):]
2333 fixpaths = os.sep != '/'
2328 fixpaths = os.sep != '/'
2334 if fixpaths:
2329 if fixpaths:
2335 spec = spec.replace(os.sep, '/')
2330 spec = spec.replace(os.sep, '/')
2336 speclen = len(spec)
2331 speclen = len(spec)
2337 fullpaths = opts['full']
2332 fullpaths = opts['full']
2338 files, dirs = set(), set()
2333 files, dirs = set(), set()
2339 adddir, addfile = dirs.add, files.add
2334 adddir, addfile = dirs.add, files.add
2340 for f, st in dirstate.iteritems():
2335 for f, st in dirstate.iteritems():
2341 if f.startswith(spec) and st[0] in acceptable:
2336 if f.startswith(spec) and st[0] in acceptable:
2342 if fixpaths:
2337 if fixpaths:
2343 f = f.replace('/', os.sep)
2338 f = f.replace('/', os.sep)
2344 if fullpaths:
2339 if fullpaths:
2345 addfile(f)
2340 addfile(f)
2346 continue
2341 continue
2347 s = f.find(os.sep, speclen)
2342 s = f.find(os.sep, speclen)
2348 if s >= 0:
2343 if s >= 0:
2349 adddir(f[:s])
2344 adddir(f[:s])
2350 else:
2345 else:
2351 addfile(f)
2346 addfile(f)
2352 return files, dirs
2347 return files, dirs
2353
2348
2354 acceptable = ''
2349 acceptable = ''
2355 if opts['normal']:
2350 if opts['normal']:
2356 acceptable += 'nm'
2351 acceptable += 'nm'
2357 if opts['added']:
2352 if opts['added']:
2358 acceptable += 'a'
2353 acceptable += 'a'
2359 if opts['removed']:
2354 if opts['removed']:
2360 acceptable += 'r'
2355 acceptable += 'r'
2361 cwd = repo.getcwd()
2356 cwd = repo.getcwd()
2362 if not specs:
2357 if not specs:
2363 specs = ['.']
2358 specs = ['.']
2364
2359
2365 files, dirs = set(), set()
2360 files, dirs = set(), set()
2366 for spec in specs:
2361 for spec in specs:
2367 f, d = complete(spec, acceptable or 'nmar')
2362 f, d = complete(spec, acceptable or 'nmar')
2368 files.update(f)
2363 files.update(f)
2369 dirs.update(d)
2364 dirs.update(d)
2370 files.update(dirs)
2365 files.update(dirs)
2371 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2366 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2372 ui.write('\n')
2367 ui.write('\n')
2373
2368
2374 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2369 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2375 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2370 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2376 '''access the pushkey key/value protocol
2371 '''access the pushkey key/value protocol
2377
2372
2378 With two args, list the keys in the given namespace.
2373 With two args, list the keys in the given namespace.
2379
2374
2380 With five args, set a key to new if it currently is set to old.
2375 With five args, set a key to new if it currently is set to old.
2381 Reports success or failure.
2376 Reports success or failure.
2382 '''
2377 '''
2383
2378
2384 target = hg.peer(ui, {}, repopath)
2379 target = hg.peer(ui, {}, repopath)
2385 if keyinfo:
2380 if keyinfo:
2386 key, old, new = keyinfo
2381 key, old, new = keyinfo
2387 r = target.pushkey(namespace, key, old, new)
2382 r = target.pushkey(namespace, key, old, new)
2388 ui.status(str(r) + '\n')
2383 ui.status(str(r) + '\n')
2389 return not r
2384 return not r
2390 else:
2385 else:
2391 for k, v in sorted(target.listkeys(namespace).iteritems()):
2386 for k, v in sorted(target.listkeys(namespace).iteritems()):
2392 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2387 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2393 v.encode('string-escape')))
2388 v.encode('string-escape')))
2394
2389
2395 @command('debugpvec', [], _('A B'))
2390 @command('debugpvec', [], _('A B'))
2396 def debugpvec(ui, repo, a, b=None):
2391 def debugpvec(ui, repo, a, b=None):
2397 ca = scmutil.revsingle(repo, a)
2392 ca = scmutil.revsingle(repo, a)
2398 cb = scmutil.revsingle(repo, b)
2393 cb = scmutil.revsingle(repo, b)
2399 pa = pvec.ctxpvec(ca)
2394 pa = pvec.ctxpvec(ca)
2400 pb = pvec.ctxpvec(cb)
2395 pb = pvec.ctxpvec(cb)
2401 if pa == pb:
2396 if pa == pb:
2402 rel = "="
2397 rel = "="
2403 elif pa > pb:
2398 elif pa > pb:
2404 rel = ">"
2399 rel = ">"
2405 elif pa < pb:
2400 elif pa < pb:
2406 rel = "<"
2401 rel = "<"
2407 elif pa | pb:
2402 elif pa | pb:
2408 rel = "|"
2403 rel = "|"
2409 ui.write(_("a: %s\n") % pa)
2404 ui.write(_("a: %s\n") % pa)
2410 ui.write(_("b: %s\n") % pb)
2405 ui.write(_("b: %s\n") % pb)
2411 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2406 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2412 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2407 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2413 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2408 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2414 pa.distance(pb), rel))
2409 pa.distance(pb), rel))
2415
2410
2416 @command('debugrebuilddirstate|debugrebuildstate',
2411 @command('debugrebuilddirstate|debugrebuildstate',
2417 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2412 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2418 _('[-r REV]'))
2413 _('[-r REV]'))
2419 def debugrebuilddirstate(ui, repo, rev):
2414 def debugrebuilddirstate(ui, repo, rev):
2420 """rebuild the dirstate as it would look like for the given revision
2415 """rebuild the dirstate as it would look like for the given revision
2421
2416
2422 If no revision is specified the first current parent will be used.
2417 If no revision is specified the first current parent will be used.
2423
2418
2424 The dirstate will be set to the files of the given revision.
2419 The dirstate will be set to the files of the given revision.
2425 The actual working directory content or existing dirstate
2420 The actual working directory content or existing dirstate
2426 information such as adds or removes is not considered.
2421 information such as adds or removes is not considered.
2427
2422
2428 One use of this command is to make the next :hg:`status` invocation
2423 One use of this command is to make the next :hg:`status` invocation
2429 check the actual file content.
2424 check the actual file content.
2430 """
2425 """
2431 ctx = scmutil.revsingle(repo, rev)
2426 ctx = scmutil.revsingle(repo, rev)
2432 wlock = repo.wlock()
2427 wlock = repo.wlock()
2433 try:
2428 try:
2434 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2429 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2435 finally:
2430 finally:
2436 wlock.release()
2431 wlock.release()
2437
2432
2438 @command('debugrename',
2433 @command('debugrename',
2439 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2434 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2440 _('[-r REV] FILE'))
2435 _('[-r REV] FILE'))
2441 def debugrename(ui, repo, file1, *pats, **opts):
2436 def debugrename(ui, repo, file1, *pats, **opts):
2442 """dump rename information"""
2437 """dump rename information"""
2443
2438
2444 ctx = scmutil.revsingle(repo, opts.get('rev'))
2439 ctx = scmutil.revsingle(repo, opts.get('rev'))
2445 m = scmutil.match(ctx, (file1,) + pats, opts)
2440 m = scmutil.match(ctx, (file1,) + pats, opts)
2446 for abs in ctx.walk(m):
2441 for abs in ctx.walk(m):
2447 fctx = ctx[abs]
2442 fctx = ctx[abs]
2448 o = fctx.filelog().renamed(fctx.filenode())
2443 o = fctx.filelog().renamed(fctx.filenode())
2449 rel = m.rel(abs)
2444 rel = m.rel(abs)
2450 if o:
2445 if o:
2451 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2446 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2452 else:
2447 else:
2453 ui.write(_("%s not renamed\n") % rel)
2448 ui.write(_("%s not renamed\n") % rel)
2454
2449
2455 @command('debugrevlog',
2450 @command('debugrevlog',
2456 [('c', 'changelog', False, _('open changelog')),
2451 [('c', 'changelog', False, _('open changelog')),
2457 ('m', 'manifest', False, _('open manifest')),
2452 ('m', 'manifest', False, _('open manifest')),
2458 ('d', 'dump', False, _('dump index data'))],
2453 ('d', 'dump', False, _('dump index data'))],
2459 _('-c|-m|FILE'))
2454 _('-c|-m|FILE'))
2460 def debugrevlog(ui, repo, file_=None, **opts):
2455 def debugrevlog(ui, repo, file_=None, **opts):
2461 """show data and statistics about a revlog"""
2456 """show data and statistics about a revlog"""
2462 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2457 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2463
2458
2464 if opts.get("dump"):
2459 if opts.get("dump"):
2465 numrevs = len(r)
2460 numrevs = len(r)
2466 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2461 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2467 " rawsize totalsize compression heads\n")
2462 " rawsize totalsize compression heads\n")
2468 ts = 0
2463 ts = 0
2469 heads = set()
2464 heads = set()
2470 for rev in xrange(numrevs):
2465 for rev in xrange(numrevs):
2471 dbase = r.deltaparent(rev)
2466 dbase = r.deltaparent(rev)
2472 if dbase == -1:
2467 if dbase == -1:
2473 dbase = rev
2468 dbase = rev
2474 cbase = r.chainbase(rev)
2469 cbase = r.chainbase(rev)
2475 p1, p2 = r.parentrevs(rev)
2470 p1, p2 = r.parentrevs(rev)
2476 rs = r.rawsize(rev)
2471 rs = r.rawsize(rev)
2477 ts = ts + rs
2472 ts = ts + rs
2478 heads -= set(r.parentrevs(rev))
2473 heads -= set(r.parentrevs(rev))
2479 heads.add(rev)
2474 heads.add(rev)
2480 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2475 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2481 (rev, p1, p2, r.start(rev), r.end(rev),
2476 (rev, p1, p2, r.start(rev), r.end(rev),
2482 r.start(dbase), r.start(cbase),
2477 r.start(dbase), r.start(cbase),
2483 r.start(p1), r.start(p2),
2478 r.start(p1), r.start(p2),
2484 rs, ts, ts / r.end(rev), len(heads)))
2479 rs, ts, ts / r.end(rev), len(heads)))
2485 return 0
2480 return 0
2486
2481
2487 v = r.version
2482 v = r.version
2488 format = v & 0xFFFF
2483 format = v & 0xFFFF
2489 flags = []
2484 flags = []
2490 gdelta = False
2485 gdelta = False
2491 if v & revlog.REVLOGNGINLINEDATA:
2486 if v & revlog.REVLOGNGINLINEDATA:
2492 flags.append('inline')
2487 flags.append('inline')
2493 if v & revlog.REVLOGGENERALDELTA:
2488 if v & revlog.REVLOGGENERALDELTA:
2494 gdelta = True
2489 gdelta = True
2495 flags.append('generaldelta')
2490 flags.append('generaldelta')
2496 if not flags:
2491 if not flags:
2497 flags = ['(none)']
2492 flags = ['(none)']
2498
2493
2499 nummerges = 0
2494 nummerges = 0
2500 numfull = 0
2495 numfull = 0
2501 numprev = 0
2496 numprev = 0
2502 nump1 = 0
2497 nump1 = 0
2503 nump2 = 0
2498 nump2 = 0
2504 numother = 0
2499 numother = 0
2505 nump1prev = 0
2500 nump1prev = 0
2506 nump2prev = 0
2501 nump2prev = 0
2507 chainlengths = []
2502 chainlengths = []
2508
2503
2509 datasize = [None, 0, 0L]
2504 datasize = [None, 0, 0L]
2510 fullsize = [None, 0, 0L]
2505 fullsize = [None, 0, 0L]
2511 deltasize = [None, 0, 0L]
2506 deltasize = [None, 0, 0L]
2512
2507
2513 def addsize(size, l):
2508 def addsize(size, l):
2514 if l[0] is None or size < l[0]:
2509 if l[0] is None or size < l[0]:
2515 l[0] = size
2510 l[0] = size
2516 if size > l[1]:
2511 if size > l[1]:
2517 l[1] = size
2512 l[1] = size
2518 l[2] += size
2513 l[2] += size
2519
2514
2520 numrevs = len(r)
2515 numrevs = len(r)
2521 for rev in xrange(numrevs):
2516 for rev in xrange(numrevs):
2522 p1, p2 = r.parentrevs(rev)
2517 p1, p2 = r.parentrevs(rev)
2523 delta = r.deltaparent(rev)
2518 delta = r.deltaparent(rev)
2524 if format > 0:
2519 if format > 0:
2525 addsize(r.rawsize(rev), datasize)
2520 addsize(r.rawsize(rev), datasize)
2526 if p2 != nullrev:
2521 if p2 != nullrev:
2527 nummerges += 1
2522 nummerges += 1
2528 size = r.length(rev)
2523 size = r.length(rev)
2529 if delta == nullrev:
2524 if delta == nullrev:
2530 chainlengths.append(0)
2525 chainlengths.append(0)
2531 numfull += 1
2526 numfull += 1
2532 addsize(size, fullsize)
2527 addsize(size, fullsize)
2533 else:
2528 else:
2534 chainlengths.append(chainlengths[delta] + 1)
2529 chainlengths.append(chainlengths[delta] + 1)
2535 addsize(size, deltasize)
2530 addsize(size, deltasize)
2536 if delta == rev - 1:
2531 if delta == rev - 1:
2537 numprev += 1
2532 numprev += 1
2538 if delta == p1:
2533 if delta == p1:
2539 nump1prev += 1
2534 nump1prev += 1
2540 elif delta == p2:
2535 elif delta == p2:
2541 nump2prev += 1
2536 nump2prev += 1
2542 elif delta == p1:
2537 elif delta == p1:
2543 nump1 += 1
2538 nump1 += 1
2544 elif delta == p2:
2539 elif delta == p2:
2545 nump2 += 1
2540 nump2 += 1
2546 elif delta != nullrev:
2541 elif delta != nullrev:
2547 numother += 1
2542 numother += 1
2548
2543
2549 # Adjust size min value for empty cases
2544 # Adjust size min value for empty cases
2550 for size in (datasize, fullsize, deltasize):
2545 for size in (datasize, fullsize, deltasize):
2551 if size[0] is None:
2546 if size[0] is None:
2552 size[0] = 0
2547 size[0] = 0
2553
2548
2554 numdeltas = numrevs - numfull
2549 numdeltas = numrevs - numfull
2555 numoprev = numprev - nump1prev - nump2prev
2550 numoprev = numprev - nump1prev - nump2prev
2556 totalrawsize = datasize[2]
2551 totalrawsize = datasize[2]
2557 datasize[2] /= numrevs
2552 datasize[2] /= numrevs
2558 fulltotal = fullsize[2]
2553 fulltotal = fullsize[2]
2559 fullsize[2] /= numfull
2554 fullsize[2] /= numfull
2560 deltatotal = deltasize[2]
2555 deltatotal = deltasize[2]
2561 if numrevs - numfull > 0:
2556 if numrevs - numfull > 0:
2562 deltasize[2] /= numrevs - numfull
2557 deltasize[2] /= numrevs - numfull
2563 totalsize = fulltotal + deltatotal
2558 totalsize = fulltotal + deltatotal
2564 avgchainlen = sum(chainlengths) / numrevs
2559 avgchainlen = sum(chainlengths) / numrevs
2565 compratio = totalrawsize / totalsize
2560 compratio = totalrawsize / totalsize
2566
2561
2567 basedfmtstr = '%%%dd\n'
2562 basedfmtstr = '%%%dd\n'
2568 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2563 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2569
2564
2570 def dfmtstr(max):
2565 def dfmtstr(max):
2571 return basedfmtstr % len(str(max))
2566 return basedfmtstr % len(str(max))
2572 def pcfmtstr(max, padding=0):
2567 def pcfmtstr(max, padding=0):
2573 return basepcfmtstr % (len(str(max)), ' ' * padding)
2568 return basepcfmtstr % (len(str(max)), ' ' * padding)
2574
2569
2575 def pcfmt(value, total):
2570 def pcfmt(value, total):
2576 return (value, 100 * float(value) / total)
2571 return (value, 100 * float(value) / total)
2577
2572
2578 ui.write(('format : %d\n') % format)
2573 ui.write(('format : %d\n') % format)
2579 ui.write(('flags : %s\n') % ', '.join(flags))
2574 ui.write(('flags : %s\n') % ', '.join(flags))
2580
2575
2581 ui.write('\n')
2576 ui.write('\n')
2582 fmt = pcfmtstr(totalsize)
2577 fmt = pcfmtstr(totalsize)
2583 fmt2 = dfmtstr(totalsize)
2578 fmt2 = dfmtstr(totalsize)
2584 ui.write(('revisions : ') + fmt2 % numrevs)
2579 ui.write(('revisions : ') + fmt2 % numrevs)
2585 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2580 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2586 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2581 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2587 ui.write(('revisions : ') + fmt2 % numrevs)
2582 ui.write(('revisions : ') + fmt2 % numrevs)
2588 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2583 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2589 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2584 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2590 ui.write(('revision size : ') + fmt2 % totalsize)
2585 ui.write(('revision size : ') + fmt2 % totalsize)
2591 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2586 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2592 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2587 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2593
2588
2594 ui.write('\n')
2589 ui.write('\n')
2595 fmt = dfmtstr(max(avgchainlen, compratio))
2590 fmt = dfmtstr(max(avgchainlen, compratio))
2596 ui.write(('avg chain length : ') + fmt % avgchainlen)
2591 ui.write(('avg chain length : ') + fmt % avgchainlen)
2597 ui.write(('compression ratio : ') + fmt % compratio)
2592 ui.write(('compression ratio : ') + fmt % compratio)
2598
2593
2599 if format > 0:
2594 if format > 0:
2600 ui.write('\n')
2595 ui.write('\n')
2601 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2596 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2602 % tuple(datasize))
2597 % tuple(datasize))
2603 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2598 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2604 % tuple(fullsize))
2599 % tuple(fullsize))
2605 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2600 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2606 % tuple(deltasize))
2601 % tuple(deltasize))
2607
2602
2608 if numdeltas > 0:
2603 if numdeltas > 0:
2609 ui.write('\n')
2604 ui.write('\n')
2610 fmt = pcfmtstr(numdeltas)
2605 fmt = pcfmtstr(numdeltas)
2611 fmt2 = pcfmtstr(numdeltas, 4)
2606 fmt2 = pcfmtstr(numdeltas, 4)
2612 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2607 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2613 if numprev > 0:
2608 if numprev > 0:
2614 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2609 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2615 numprev))
2610 numprev))
2616 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2611 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2617 numprev))
2612 numprev))
2618 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2613 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2619 numprev))
2614 numprev))
2620 if gdelta:
2615 if gdelta:
2621 ui.write(('deltas against p1 : ')
2616 ui.write(('deltas against p1 : ')
2622 + fmt % pcfmt(nump1, numdeltas))
2617 + fmt % pcfmt(nump1, numdeltas))
2623 ui.write(('deltas against p2 : ')
2618 ui.write(('deltas against p2 : ')
2624 + fmt % pcfmt(nump2, numdeltas))
2619 + fmt % pcfmt(nump2, numdeltas))
2625 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2620 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2626 numdeltas))
2621 numdeltas))
2627
2622
2628 @command('debugrevspec',
2623 @command('debugrevspec',
2629 [('', 'optimize', None, _('print parsed tree after optimizing'))],
2624 [('', 'optimize', None, _('print parsed tree after optimizing'))],
2630 ('REVSPEC'))
2625 ('REVSPEC'))
2631 def debugrevspec(ui, repo, expr, **opts):
2626 def debugrevspec(ui, repo, expr, **opts):
2632 """parse and apply a revision specification
2627 """parse and apply a revision specification
2633
2628
2634 Use --verbose to print the parsed tree before and after aliases
2629 Use --verbose to print the parsed tree before and after aliases
2635 expansion.
2630 expansion.
2636 """
2631 """
2637 if ui.verbose:
2632 if ui.verbose:
2638 tree = revset.parse(expr)[0]
2633 tree = revset.parse(expr)[0]
2639 ui.note(revset.prettyformat(tree), "\n")
2634 ui.note(revset.prettyformat(tree), "\n")
2640 newtree = revset.findaliases(ui, tree)
2635 newtree = revset.findaliases(ui, tree)
2641 if newtree != tree:
2636 if newtree != tree:
2642 ui.note(revset.prettyformat(newtree), "\n")
2637 ui.note(revset.prettyformat(newtree), "\n")
2643 if opts["optimize"]:
2638 if opts["optimize"]:
2644 weight, optimizedtree = revset.optimize(newtree, True)
2639 weight, optimizedtree = revset.optimize(newtree, True)
2645 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
2640 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
2646 func = revset.match(ui, expr)
2641 func = revset.match(ui, expr)
2647 for c in func(repo, revset.spanset(repo)):
2642 for c in func(repo, revset.spanset(repo)):
2648 ui.write("%s\n" % c)
2643 ui.write("%s\n" % c)
2649
2644
2650 @command('debugsetparents', [], _('REV1 [REV2]'))
2645 @command('debugsetparents', [], _('REV1 [REV2]'))
2651 def debugsetparents(ui, repo, rev1, rev2=None):
2646 def debugsetparents(ui, repo, rev1, rev2=None):
2652 """manually set the parents of the current working directory
2647 """manually set the parents of the current working directory
2653
2648
2654 This is useful for writing repository conversion tools, but should
2649 This is useful for writing repository conversion tools, but should
2655 be used with care.
2650 be used with care.
2656
2651
2657 Returns 0 on success.
2652 Returns 0 on success.
2658 """
2653 """
2659
2654
2660 r1 = scmutil.revsingle(repo, rev1).node()
2655 r1 = scmutil.revsingle(repo, rev1).node()
2661 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2656 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2662
2657
2663 wlock = repo.wlock()
2658 wlock = repo.wlock()
2664 try:
2659 try:
2665 repo.setparents(r1, r2)
2660 repo.setparents(r1, r2)
2666 finally:
2661 finally:
2667 wlock.release()
2662 wlock.release()
2668
2663
2669 @command('debugdirstate|debugstate',
2664 @command('debugdirstate|debugstate',
2670 [('', 'nodates', None, _('do not display the saved mtime')),
2665 [('', 'nodates', None, _('do not display the saved mtime')),
2671 ('', 'datesort', None, _('sort by saved mtime'))],
2666 ('', 'datesort', None, _('sort by saved mtime'))],
2672 _('[OPTION]...'))
2667 _('[OPTION]...'))
2673 def debugstate(ui, repo, nodates=None, datesort=None):
2668 def debugstate(ui, repo, nodates=None, datesort=None):
2674 """show the contents of the current dirstate"""
2669 """show the contents of the current dirstate"""
2675 timestr = ""
2670 timestr = ""
2676 showdate = not nodates
2671 showdate = not nodates
2677 if datesort:
2672 if datesort:
2678 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2673 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2679 else:
2674 else:
2680 keyfunc = None # sort by filename
2675 keyfunc = None # sort by filename
2681 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2676 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2682 if showdate:
2677 if showdate:
2683 if ent[3] == -1:
2678 if ent[3] == -1:
2684 # Pad or slice to locale representation
2679 # Pad or slice to locale representation
2685 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2680 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2686 time.localtime(0)))
2681 time.localtime(0)))
2687 timestr = 'unset'
2682 timestr = 'unset'
2688 timestr = (timestr[:locale_len] +
2683 timestr = (timestr[:locale_len] +
2689 ' ' * (locale_len - len(timestr)))
2684 ' ' * (locale_len - len(timestr)))
2690 else:
2685 else:
2691 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2686 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2692 time.localtime(ent[3]))
2687 time.localtime(ent[3]))
2693 if ent[1] & 020000:
2688 if ent[1] & 020000:
2694 mode = 'lnk'
2689 mode = 'lnk'
2695 else:
2690 else:
2696 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2691 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2697 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2692 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2698 for f in repo.dirstate.copies():
2693 for f in repo.dirstate.copies():
2699 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2694 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2700
2695
2701 @command('debugsub',
2696 @command('debugsub',
2702 [('r', 'rev', '',
2697 [('r', 'rev', '',
2703 _('revision to check'), _('REV'))],
2698 _('revision to check'), _('REV'))],
2704 _('[-r REV] [REV]'))
2699 _('[-r REV] [REV]'))
2705 def debugsub(ui, repo, rev=None):
2700 def debugsub(ui, repo, rev=None):
2706 ctx = scmutil.revsingle(repo, rev, None)
2701 ctx = scmutil.revsingle(repo, rev, None)
2707 for k, v in sorted(ctx.substate.items()):
2702 for k, v in sorted(ctx.substate.items()):
2708 ui.write(('path %s\n') % k)
2703 ui.write(('path %s\n') % k)
2709 ui.write((' source %s\n') % v[0])
2704 ui.write((' source %s\n') % v[0])
2710 ui.write((' revision %s\n') % v[1])
2705 ui.write((' revision %s\n') % v[1])
2711
2706
2712 @command('debugsuccessorssets',
2707 @command('debugsuccessorssets',
2713 [],
2708 [],
2714 _('[REV]'))
2709 _('[REV]'))
2715 def debugsuccessorssets(ui, repo, *revs):
2710 def debugsuccessorssets(ui, repo, *revs):
2716 """show set of successors for revision
2711 """show set of successors for revision
2717
2712
2718 A successors set of changeset A is a consistent group of revisions that
2713 A successors set of changeset A is a consistent group of revisions that
2719 succeed A. It contains non-obsolete changesets only.
2714 succeed A. It contains non-obsolete changesets only.
2720
2715
2721 In most cases a changeset A has a single successors set containing a single
2716 In most cases a changeset A has a single successors set containing a single
2722 successor (changeset A replaced by A').
2717 successor (changeset A replaced by A').
2723
2718
2724 A changeset that is made obsolete with no successors are called "pruned".
2719 A changeset that is made obsolete with no successors are called "pruned".
2725 Such changesets have no successors sets at all.
2720 Such changesets have no successors sets at all.
2726
2721
2727 A changeset that has been "split" will have a successors set containing
2722 A changeset that has been "split" will have a successors set containing
2728 more than one successor.
2723 more than one successor.
2729
2724
2730 A changeset that has been rewritten in multiple different ways is called
2725 A changeset that has been rewritten in multiple different ways is called
2731 "divergent". Such changesets have multiple successor sets (each of which
2726 "divergent". Such changesets have multiple successor sets (each of which
2732 may also be split, i.e. have multiple successors).
2727 may also be split, i.e. have multiple successors).
2733
2728
2734 Results are displayed as follows::
2729 Results are displayed as follows::
2735
2730
2736 <rev1>
2731 <rev1>
2737 <successors-1A>
2732 <successors-1A>
2738 <rev2>
2733 <rev2>
2739 <successors-2A>
2734 <successors-2A>
2740 <successors-2B1> <successors-2B2> <successors-2B3>
2735 <successors-2B1> <successors-2B2> <successors-2B3>
2741
2736
2742 Here rev2 has two possible (i.e. divergent) successors sets. The first
2737 Here rev2 has two possible (i.e. divergent) successors sets. The first
2743 holds one element, whereas the second holds three (i.e. the changeset has
2738 holds one element, whereas the second holds three (i.e. the changeset has
2744 been split).
2739 been split).
2745 """
2740 """
2746 # passed to successorssets caching computation from one call to another
2741 # passed to successorssets caching computation from one call to another
2747 cache = {}
2742 cache = {}
2748 ctx2str = str
2743 ctx2str = str
2749 node2str = short
2744 node2str = short
2750 if ui.debug():
2745 if ui.debug():
2751 def ctx2str(ctx):
2746 def ctx2str(ctx):
2752 return ctx.hex()
2747 return ctx.hex()
2753 node2str = hex
2748 node2str = hex
2754 for rev in scmutil.revrange(repo, revs):
2749 for rev in scmutil.revrange(repo, revs):
2755 ctx = repo[rev]
2750 ctx = repo[rev]
2756 ui.write('%s\n'% ctx2str(ctx))
2751 ui.write('%s\n'% ctx2str(ctx))
2757 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2752 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2758 if succsset:
2753 if succsset:
2759 ui.write(' ')
2754 ui.write(' ')
2760 ui.write(node2str(succsset[0]))
2755 ui.write(node2str(succsset[0]))
2761 for node in succsset[1:]:
2756 for node in succsset[1:]:
2762 ui.write(' ')
2757 ui.write(' ')
2763 ui.write(node2str(node))
2758 ui.write(node2str(node))
2764 ui.write('\n')
2759 ui.write('\n')
2765
2760
2766 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2761 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2767 def debugwalk(ui, repo, *pats, **opts):
2762 def debugwalk(ui, repo, *pats, **opts):
2768 """show how files match on given patterns"""
2763 """show how files match on given patterns"""
2769 m = scmutil.match(repo[None], pats, opts)
2764 m = scmutil.match(repo[None], pats, opts)
2770 items = list(repo.walk(m))
2765 items = list(repo.walk(m))
2771 if not items:
2766 if not items:
2772 return
2767 return
2773 f = lambda fn: fn
2768 f = lambda fn: fn
2774 if ui.configbool('ui', 'slash') and os.sep != '/':
2769 if ui.configbool('ui', 'slash') and os.sep != '/':
2775 f = lambda fn: util.normpath(fn)
2770 f = lambda fn: util.normpath(fn)
2776 fmt = 'f %%-%ds %%-%ds %%s' % (
2771 fmt = 'f %%-%ds %%-%ds %%s' % (
2777 max([len(abs) for abs in items]),
2772 max([len(abs) for abs in items]),
2778 max([len(m.rel(abs)) for abs in items]))
2773 max([len(m.rel(abs)) for abs in items]))
2779 for abs in items:
2774 for abs in items:
2780 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2775 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2781 ui.write("%s\n" % line.rstrip())
2776 ui.write("%s\n" % line.rstrip())
2782
2777
2783 @command('debugwireargs',
2778 @command('debugwireargs',
2784 [('', 'three', '', 'three'),
2779 [('', 'three', '', 'three'),
2785 ('', 'four', '', 'four'),
2780 ('', 'four', '', 'four'),
2786 ('', 'five', '', 'five'),
2781 ('', 'five', '', 'five'),
2787 ] + remoteopts,
2782 ] + remoteopts,
2788 _('REPO [OPTIONS]... [ONE [TWO]]'))
2783 _('REPO [OPTIONS]... [ONE [TWO]]'))
2789 def debugwireargs(ui, repopath, *vals, **opts):
2784 def debugwireargs(ui, repopath, *vals, **opts):
2790 repo = hg.peer(ui, opts, repopath)
2785 repo = hg.peer(ui, opts, repopath)
2791 for opt in remoteopts:
2786 for opt in remoteopts:
2792 del opts[opt[1]]
2787 del opts[opt[1]]
2793 args = {}
2788 args = {}
2794 for k, v in opts.iteritems():
2789 for k, v in opts.iteritems():
2795 if v:
2790 if v:
2796 args[k] = v
2791 args[k] = v
2797 # run twice to check that we don't mess up the stream for the next command
2792 # run twice to check that we don't mess up the stream for the next command
2798 res1 = repo.debugwireargs(*vals, **args)
2793 res1 = repo.debugwireargs(*vals, **args)
2799 res2 = repo.debugwireargs(*vals, **args)
2794 res2 = repo.debugwireargs(*vals, **args)
2800 ui.write("%s\n" % res1)
2795 ui.write("%s\n" % res1)
2801 if res1 != res2:
2796 if res1 != res2:
2802 ui.warn("%s\n" % res2)
2797 ui.warn("%s\n" % res2)
2803
2798
2804 @command('^diff',
2799 @command('^diff',
2805 [('r', 'rev', [], _('revision'), _('REV')),
2800 [('r', 'rev', [], _('revision'), _('REV')),
2806 ('c', 'change', '', _('change made by revision'), _('REV'))
2801 ('c', 'change', '', _('change made by revision'), _('REV'))
2807 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2802 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2808 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2803 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2809 def diff(ui, repo, *pats, **opts):
2804 def diff(ui, repo, *pats, **opts):
2810 """diff repository (or selected files)
2805 """diff repository (or selected files)
2811
2806
2812 Show differences between revisions for the specified files.
2807 Show differences between revisions for the specified files.
2813
2808
2814 Differences between files are shown using the unified diff format.
2809 Differences between files are shown using the unified diff format.
2815
2810
2816 .. note::
2811 .. note::
2817
2812
2818 diff may generate unexpected results for merges, as it will
2813 diff may generate unexpected results for merges, as it will
2819 default to comparing against the working directory's first
2814 default to comparing against the working directory's first
2820 parent changeset if no revisions are specified.
2815 parent changeset if no revisions are specified.
2821
2816
2822 When two revision arguments are given, then changes are shown
2817 When two revision arguments are given, then changes are shown
2823 between those revisions. If only one revision is specified then
2818 between those revisions. If only one revision is specified then
2824 that revision is compared to the working directory, and, when no
2819 that revision is compared to the working directory, and, when no
2825 revisions are specified, the working directory files are compared
2820 revisions are specified, the working directory files are compared
2826 to its parent.
2821 to its parent.
2827
2822
2828 Alternatively you can specify -c/--change with a revision to see
2823 Alternatively you can specify -c/--change with a revision to see
2829 the changes in that changeset relative to its first parent.
2824 the changes in that changeset relative to its first parent.
2830
2825
2831 Without the -a/--text option, diff will avoid generating diffs of
2826 Without the -a/--text option, diff will avoid generating diffs of
2832 files it detects as binary. With -a, diff will generate a diff
2827 files it detects as binary. With -a, diff will generate a diff
2833 anyway, probably with undesirable results.
2828 anyway, probably with undesirable results.
2834
2829
2835 Use the -g/--git option to generate diffs in the git extended diff
2830 Use the -g/--git option to generate diffs in the git extended diff
2836 format. For more information, read :hg:`help diffs`.
2831 format. For more information, read :hg:`help diffs`.
2837
2832
2838 .. container:: verbose
2833 .. container:: verbose
2839
2834
2840 Examples:
2835 Examples:
2841
2836
2842 - compare a file in the current working directory to its parent::
2837 - compare a file in the current working directory to its parent::
2843
2838
2844 hg diff foo.c
2839 hg diff foo.c
2845
2840
2846 - compare two historical versions of a directory, with rename info::
2841 - compare two historical versions of a directory, with rename info::
2847
2842
2848 hg diff --git -r 1.0:1.2 lib/
2843 hg diff --git -r 1.0:1.2 lib/
2849
2844
2850 - get change stats relative to the last change on some date::
2845 - get change stats relative to the last change on some date::
2851
2846
2852 hg diff --stat -r "date('may 2')"
2847 hg diff --stat -r "date('may 2')"
2853
2848
2854 - diff all newly-added files that contain a keyword::
2849 - diff all newly-added files that contain a keyword::
2855
2850
2856 hg diff "set:added() and grep(GNU)"
2851 hg diff "set:added() and grep(GNU)"
2857
2852
2858 - compare a revision and its parents::
2853 - compare a revision and its parents::
2859
2854
2860 hg diff -c 9353 # compare against first parent
2855 hg diff -c 9353 # compare against first parent
2861 hg diff -r 9353^:9353 # same using revset syntax
2856 hg diff -r 9353^:9353 # same using revset syntax
2862 hg diff -r 9353^2:9353 # compare against the second parent
2857 hg diff -r 9353^2:9353 # compare against the second parent
2863
2858
2864 Returns 0 on success.
2859 Returns 0 on success.
2865 """
2860 """
2866
2861
2867 revs = opts.get('rev')
2862 revs = opts.get('rev')
2868 change = opts.get('change')
2863 change = opts.get('change')
2869 stat = opts.get('stat')
2864 stat = opts.get('stat')
2870 reverse = opts.get('reverse')
2865 reverse = opts.get('reverse')
2871
2866
2872 if revs and change:
2867 if revs and change:
2873 msg = _('cannot specify --rev and --change at the same time')
2868 msg = _('cannot specify --rev and --change at the same time')
2874 raise util.Abort(msg)
2869 raise util.Abort(msg)
2875 elif change:
2870 elif change:
2876 node2 = scmutil.revsingle(repo, change, None).node()
2871 node2 = scmutil.revsingle(repo, change, None).node()
2877 node1 = repo[node2].p1().node()
2872 node1 = repo[node2].p1().node()
2878 else:
2873 else:
2879 node1, node2 = scmutil.revpair(repo, revs)
2874 node1, node2 = scmutil.revpair(repo, revs)
2880
2875
2881 if reverse:
2876 if reverse:
2882 node1, node2 = node2, node1
2877 node1, node2 = node2, node1
2883
2878
2884 diffopts = patch.diffopts(ui, opts)
2879 diffopts = patch.diffopts(ui, opts)
2885 m = scmutil.match(repo[node2], pats, opts)
2880 m = scmutil.match(repo[node2], pats, opts)
2886 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2881 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2887 listsubrepos=opts.get('subrepos'))
2882 listsubrepos=opts.get('subrepos'))
2888
2883
2889 @command('^export',
2884 @command('^export',
2890 [('o', 'output', '',
2885 [('o', 'output', '',
2891 _('print output to file with formatted name'), _('FORMAT')),
2886 _('print output to file with formatted name'), _('FORMAT')),
2892 ('', 'switch-parent', None, _('diff against the second parent')),
2887 ('', 'switch-parent', None, _('diff against the second parent')),
2893 ('r', 'rev', [], _('revisions to export'), _('REV')),
2888 ('r', 'rev', [], _('revisions to export'), _('REV')),
2894 ] + diffopts,
2889 ] + diffopts,
2895 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2890 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2896 def export(ui, repo, *changesets, **opts):
2891 def export(ui, repo, *changesets, **opts):
2897 """dump the header and diffs for one or more changesets
2892 """dump the header and diffs for one or more changesets
2898
2893
2899 Print the changeset header and diffs for one or more revisions.
2894 Print the changeset header and diffs for one or more revisions.
2900 If no revision is given, the parent of the working directory is used.
2895 If no revision is given, the parent of the working directory is used.
2901
2896
2902 The information shown in the changeset header is: author, date,
2897 The information shown in the changeset header is: author, date,
2903 branch name (if non-default), changeset hash, parent(s) and commit
2898 branch name (if non-default), changeset hash, parent(s) and commit
2904 comment.
2899 comment.
2905
2900
2906 .. note::
2901 .. note::
2907
2902
2908 export may generate unexpected diff output for merge
2903 export may generate unexpected diff output for merge
2909 changesets, as it will compare the merge changeset against its
2904 changesets, as it will compare the merge changeset against its
2910 first parent only.
2905 first parent only.
2911
2906
2912 Output may be to a file, in which case the name of the file is
2907 Output may be to a file, in which case the name of the file is
2913 given using a format string. The formatting rules are as follows:
2908 given using a format string. The formatting rules are as follows:
2914
2909
2915 :``%%``: literal "%" character
2910 :``%%``: literal "%" character
2916 :``%H``: changeset hash (40 hexadecimal digits)
2911 :``%H``: changeset hash (40 hexadecimal digits)
2917 :``%N``: number of patches being generated
2912 :``%N``: number of patches being generated
2918 :``%R``: changeset revision number
2913 :``%R``: changeset revision number
2919 :``%b``: basename of the exporting repository
2914 :``%b``: basename of the exporting repository
2920 :``%h``: short-form changeset hash (12 hexadecimal digits)
2915 :``%h``: short-form changeset hash (12 hexadecimal digits)
2921 :``%m``: first line of the commit message (only alphanumeric characters)
2916 :``%m``: first line of the commit message (only alphanumeric characters)
2922 :``%n``: zero-padded sequence number, starting at 1
2917 :``%n``: zero-padded sequence number, starting at 1
2923 :``%r``: zero-padded changeset revision number
2918 :``%r``: zero-padded changeset revision number
2924
2919
2925 Without the -a/--text option, export will avoid generating diffs
2920 Without the -a/--text option, export will avoid generating diffs
2926 of files it detects as binary. With -a, export will generate a
2921 of files it detects as binary. With -a, export will generate a
2927 diff anyway, probably with undesirable results.
2922 diff anyway, probably with undesirable results.
2928
2923
2929 Use the -g/--git option to generate diffs in the git extended diff
2924 Use the -g/--git option to generate diffs in the git extended diff
2930 format. See :hg:`help diffs` for more information.
2925 format. See :hg:`help diffs` for more information.
2931
2926
2932 With the --switch-parent option, the diff will be against the
2927 With the --switch-parent option, the diff will be against the
2933 second parent. It can be useful to review a merge.
2928 second parent. It can be useful to review a merge.
2934
2929
2935 .. container:: verbose
2930 .. container:: verbose
2936
2931
2937 Examples:
2932 Examples:
2938
2933
2939 - use export and import to transplant a bugfix to the current
2934 - use export and import to transplant a bugfix to the current
2940 branch::
2935 branch::
2941
2936
2942 hg export -r 9353 | hg import -
2937 hg export -r 9353 | hg import -
2943
2938
2944 - export all the changesets between two revisions to a file with
2939 - export all the changesets between two revisions to a file with
2945 rename information::
2940 rename information::
2946
2941
2947 hg export --git -r 123:150 > changes.txt
2942 hg export --git -r 123:150 > changes.txt
2948
2943
2949 - split outgoing changes into a series of patches with
2944 - split outgoing changes into a series of patches with
2950 descriptive names::
2945 descriptive names::
2951
2946
2952 hg export -r "outgoing()" -o "%n-%m.patch"
2947 hg export -r "outgoing()" -o "%n-%m.patch"
2953
2948
2954 Returns 0 on success.
2949 Returns 0 on success.
2955 """
2950 """
2956 changesets += tuple(opts.get('rev', []))
2951 changesets += tuple(opts.get('rev', []))
2957 if not changesets:
2952 if not changesets:
2958 changesets = ['.']
2953 changesets = ['.']
2959 revs = scmutil.revrange(repo, changesets)
2954 revs = scmutil.revrange(repo, changesets)
2960 if not revs:
2955 if not revs:
2961 raise util.Abort(_("export requires at least one changeset"))
2956 raise util.Abort(_("export requires at least one changeset"))
2962 if len(revs) > 1:
2957 if len(revs) > 1:
2963 ui.note(_('exporting patches:\n'))
2958 ui.note(_('exporting patches:\n'))
2964 else:
2959 else:
2965 ui.note(_('exporting patch:\n'))
2960 ui.note(_('exporting patch:\n'))
2966 cmdutil.export(repo, revs, template=opts.get('output'),
2961 cmdutil.export(repo, revs, template=opts.get('output'),
2967 switch_parent=opts.get('switch_parent'),
2962 switch_parent=opts.get('switch_parent'),
2968 opts=patch.diffopts(ui, opts))
2963 opts=patch.diffopts(ui, opts))
2969
2964
2970 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2965 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2971 def forget(ui, repo, *pats, **opts):
2966 def forget(ui, repo, *pats, **opts):
2972 """forget the specified files on the next commit
2967 """forget the specified files on the next commit
2973
2968
2974 Mark the specified files so they will no longer be tracked
2969 Mark the specified files so they will no longer be tracked
2975 after the next commit.
2970 after the next commit.
2976
2971
2977 This only removes files from the current branch, not from the
2972 This only removes files from the current branch, not from the
2978 entire project history, and it does not delete them from the
2973 entire project history, and it does not delete them from the
2979 working directory.
2974 working directory.
2980
2975
2981 To undo a forget before the next commit, see :hg:`add`.
2976 To undo a forget before the next commit, see :hg:`add`.
2982
2977
2983 .. container:: verbose
2978 .. container:: verbose
2984
2979
2985 Examples:
2980 Examples:
2986
2981
2987 - forget newly-added binary files::
2982 - forget newly-added binary files::
2988
2983
2989 hg forget "set:added() and binary()"
2984 hg forget "set:added() and binary()"
2990
2985
2991 - forget files that would be excluded by .hgignore::
2986 - forget files that would be excluded by .hgignore::
2992
2987
2993 hg forget "set:hgignore()"
2988 hg forget "set:hgignore()"
2994
2989
2995 Returns 0 on success.
2990 Returns 0 on success.
2996 """
2991 """
2997
2992
2998 if not pats:
2993 if not pats:
2999 raise util.Abort(_('no files specified'))
2994 raise util.Abort(_('no files specified'))
3000
2995
3001 m = scmutil.match(repo[None], pats, opts)
2996 m = scmutil.match(repo[None], pats, opts)
3002 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2997 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3003 return rejected and 1 or 0
2998 return rejected and 1 or 0
3004
2999
3005 @command(
3000 @command(
3006 'graft',
3001 'graft',
3007 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3002 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3008 ('c', 'continue', False, _('resume interrupted graft')),
3003 ('c', 'continue', False, _('resume interrupted graft')),
3009 ('e', 'edit', False, _('invoke editor on commit messages')),
3004 ('e', 'edit', False, _('invoke editor on commit messages')),
3010 ('', 'log', None, _('append graft info to log message')),
3005 ('', 'log', None, _('append graft info to log message')),
3011 ('D', 'currentdate', False,
3006 ('D', 'currentdate', False,
3012 _('record the current date as commit date')),
3007 _('record the current date as commit date')),
3013 ('U', 'currentuser', False,
3008 ('U', 'currentuser', False,
3014 _('record the current user as committer'), _('DATE'))]
3009 _('record the current user as committer'), _('DATE'))]
3015 + commitopts2 + mergetoolopts + dryrunopts,
3010 + commitopts2 + mergetoolopts + dryrunopts,
3016 _('[OPTION]... [-r] REV...'))
3011 _('[OPTION]... [-r] REV...'))
3017 def graft(ui, repo, *revs, **opts):
3012 def graft(ui, repo, *revs, **opts):
3018 '''copy changes from other branches onto the current branch
3013 '''copy changes from other branches onto the current branch
3019
3014
3020 This command uses Mercurial's merge logic to copy individual
3015 This command uses Mercurial's merge logic to copy individual
3021 changes from other branches without merging branches in the
3016 changes from other branches without merging branches in the
3022 history graph. This is sometimes known as 'backporting' or
3017 history graph. This is sometimes known as 'backporting' or
3023 'cherry-picking'. By default, graft will copy user, date, and
3018 'cherry-picking'. By default, graft will copy user, date, and
3024 description from the source changesets.
3019 description from the source changesets.
3025
3020
3026 Changesets that are ancestors of the current revision, that have
3021 Changesets that are ancestors of the current revision, that have
3027 already been grafted, or that are merges will be skipped.
3022 already been grafted, or that are merges will be skipped.
3028
3023
3029 If --log is specified, log messages will have a comment appended
3024 If --log is specified, log messages will have a comment appended
3030 of the form::
3025 of the form::
3031
3026
3032 (grafted from CHANGESETHASH)
3027 (grafted from CHANGESETHASH)
3033
3028
3034 If a graft merge results in conflicts, the graft process is
3029 If a graft merge results in conflicts, the graft process is
3035 interrupted so that the current merge can be manually resolved.
3030 interrupted so that the current merge can be manually resolved.
3036 Once all conflicts are addressed, the graft process can be
3031 Once all conflicts are addressed, the graft process can be
3037 continued with the -c/--continue option.
3032 continued with the -c/--continue option.
3038
3033
3039 .. note::
3034 .. note::
3040
3035
3041 The -c/--continue option does not reapply earlier options.
3036 The -c/--continue option does not reapply earlier options.
3042
3037
3043 .. container:: verbose
3038 .. container:: verbose
3044
3039
3045 Examples:
3040 Examples:
3046
3041
3047 - copy a single change to the stable branch and edit its description::
3042 - copy a single change to the stable branch and edit its description::
3048
3043
3049 hg update stable
3044 hg update stable
3050 hg graft --edit 9393
3045 hg graft --edit 9393
3051
3046
3052 - graft a range of changesets with one exception, updating dates::
3047 - graft a range of changesets with one exception, updating dates::
3053
3048
3054 hg graft -D "2085::2093 and not 2091"
3049 hg graft -D "2085::2093 and not 2091"
3055
3050
3056 - continue a graft after resolving conflicts::
3051 - continue a graft after resolving conflicts::
3057
3052
3058 hg graft -c
3053 hg graft -c
3059
3054
3060 - show the source of a grafted changeset::
3055 - show the source of a grafted changeset::
3061
3056
3062 hg log --debug -r .
3057 hg log --debug -r .
3063
3058
3064 Returns 0 on successful completion.
3059 Returns 0 on successful completion.
3065 '''
3060 '''
3066
3061
3067 revs = list(revs)
3062 revs = list(revs)
3068 revs.extend(opts['rev'])
3063 revs.extend(opts['rev'])
3069
3064
3070 if not opts.get('user') and opts.get('currentuser'):
3065 if not opts.get('user') and opts.get('currentuser'):
3071 opts['user'] = ui.username()
3066 opts['user'] = ui.username()
3072 if not opts.get('date') and opts.get('currentdate'):
3067 if not opts.get('date') and opts.get('currentdate'):
3073 opts['date'] = "%d %d" % util.makedate()
3068 opts['date'] = "%d %d" % util.makedate()
3074
3069
3075 editor = None
3070 editor = None
3076 if opts.get('edit'):
3071 if opts.get('edit'):
3077 editor = cmdutil.commitforceeditor
3072 editor = cmdutil.commitforceeditor
3078
3073
3079 cont = False
3074 cont = False
3080 if opts['continue']:
3075 if opts['continue']:
3081 cont = True
3076 cont = True
3082 if revs:
3077 if revs:
3083 raise util.Abort(_("can't specify --continue and revisions"))
3078 raise util.Abort(_("can't specify --continue and revisions"))
3084 # read in unfinished revisions
3079 # read in unfinished revisions
3085 try:
3080 try:
3086 nodes = repo.opener.read('graftstate').splitlines()
3081 nodes = repo.opener.read('graftstate').splitlines()
3087 revs = [repo[node].rev() for node in nodes]
3082 revs = [repo[node].rev() for node in nodes]
3088 except IOError, inst:
3083 except IOError, inst:
3089 if inst.errno != errno.ENOENT:
3084 if inst.errno != errno.ENOENT:
3090 raise
3085 raise
3091 raise util.Abort(_("no graft state found, can't continue"))
3086 raise util.Abort(_("no graft state found, can't continue"))
3092 else:
3087 else:
3093 cmdutil.checkunfinished(repo)
3088 cmdutil.checkunfinished(repo)
3094 cmdutil.bailifchanged(repo)
3089 cmdutil.bailifchanged(repo)
3095 if not revs:
3090 if not revs:
3096 raise util.Abort(_('no revisions specified'))
3091 raise util.Abort(_('no revisions specified'))
3097 revs = scmutil.revrange(repo, revs)
3092 revs = scmutil.revrange(repo, revs)
3098
3093
3099 # check for merges
3094 # check for merges
3100 for rev in repo.revs('%ld and merge()', revs):
3095 for rev in repo.revs('%ld and merge()', revs):
3101 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3096 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3102 revs.remove(rev)
3097 revs.remove(rev)
3103 if not revs:
3098 if not revs:
3104 return -1
3099 return -1
3105
3100
3106 # check for ancestors of dest branch
3101 # check for ancestors of dest branch
3107 crev = repo['.'].rev()
3102 crev = repo['.'].rev()
3108 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3103 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3109 # don't mutate while iterating, create a copy
3104 # don't mutate while iterating, create a copy
3110 for rev in list(revs):
3105 for rev in list(revs):
3111 if rev in ancestors:
3106 if rev in ancestors:
3112 ui.warn(_('skipping ancestor revision %s\n') % rev)
3107 ui.warn(_('skipping ancestor revision %s\n') % rev)
3113 revs.remove(rev)
3108 revs.remove(rev)
3114 if not revs:
3109 if not revs:
3115 return -1
3110 return -1
3116
3111
3117 # analyze revs for earlier grafts
3112 # analyze revs for earlier grafts
3118 ids = {}
3113 ids = {}
3119 for ctx in repo.set("%ld", revs):
3114 for ctx in repo.set("%ld", revs):
3120 ids[ctx.hex()] = ctx.rev()
3115 ids[ctx.hex()] = ctx.rev()
3121 n = ctx.extra().get('source')
3116 n = ctx.extra().get('source')
3122 if n:
3117 if n:
3123 ids[n] = ctx.rev()
3118 ids[n] = ctx.rev()
3124
3119
3125 # check ancestors for earlier grafts
3120 # check ancestors for earlier grafts
3126 ui.debug('scanning for duplicate grafts\n')
3121 ui.debug('scanning for duplicate grafts\n')
3127
3122
3128 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3123 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3129 ctx = repo[rev]
3124 ctx = repo[rev]
3130 n = ctx.extra().get('source')
3125 n = ctx.extra().get('source')
3131 if n in ids:
3126 if n in ids:
3132 r = repo[n].rev()
3127 r = repo[n].rev()
3133 if r in revs:
3128 if r in revs:
3134 ui.warn(_('skipping revision %s (already grafted to %s)\n')
3129 ui.warn(_('skipping revision %s (already grafted to %s)\n')
3135 % (r, rev))
3130 % (r, rev))
3136 revs.remove(r)
3131 revs.remove(r)
3137 elif ids[n] in revs:
3132 elif ids[n] in revs:
3138 ui.warn(_('skipping already grafted revision %s '
3133 ui.warn(_('skipping already grafted revision %s '
3139 '(%s also has origin %d)\n') % (ids[n], rev, r))
3134 '(%s also has origin %d)\n') % (ids[n], rev, r))
3140 revs.remove(ids[n])
3135 revs.remove(ids[n])
3141 elif ctx.hex() in ids:
3136 elif ctx.hex() in ids:
3142 r = ids[ctx.hex()]
3137 r = ids[ctx.hex()]
3143 ui.warn(_('skipping already grafted revision %s '
3138 ui.warn(_('skipping already grafted revision %s '
3144 '(was grafted from %d)\n') % (r, rev))
3139 '(was grafted from %d)\n') % (r, rev))
3145 revs.remove(r)
3140 revs.remove(r)
3146 if not revs:
3141 if not revs:
3147 return -1
3142 return -1
3148
3143
3149 wlock = repo.wlock()
3144 wlock = repo.wlock()
3150 try:
3145 try:
3151 current = repo['.']
3146 current = repo['.']
3152 for pos, ctx in enumerate(repo.set("%ld", revs)):
3147 for pos, ctx in enumerate(repo.set("%ld", revs)):
3153
3148
3154 ui.status(_('grafting revision %s\n') % ctx.rev())
3149 ui.status(_('grafting revision %s\n') % ctx.rev())
3155 if opts.get('dry_run'):
3150 if opts.get('dry_run'):
3156 continue
3151 continue
3157
3152
3158 source = ctx.extra().get('source')
3153 source = ctx.extra().get('source')
3159 if not source:
3154 if not source:
3160 source = ctx.hex()
3155 source = ctx.hex()
3161 extra = {'source': source}
3156 extra = {'source': source}
3162 user = ctx.user()
3157 user = ctx.user()
3163 if opts.get('user'):
3158 if opts.get('user'):
3164 user = opts['user']
3159 user = opts['user']
3165 date = ctx.date()
3160 date = ctx.date()
3166 if opts.get('date'):
3161 if opts.get('date'):
3167 date = opts['date']
3162 date = opts['date']
3168 message = ctx.description()
3163 message = ctx.description()
3169 if opts.get('log'):
3164 if opts.get('log'):
3170 message += '\n(grafted from %s)' % ctx.hex()
3165 message += '\n(grafted from %s)' % ctx.hex()
3171
3166
3172 # we don't merge the first commit when continuing
3167 # we don't merge the first commit when continuing
3173 if not cont:
3168 if not cont:
3174 # perform the graft merge with p1(rev) as 'ancestor'
3169 # perform the graft merge with p1(rev) as 'ancestor'
3175 try:
3170 try:
3176 # ui.forcemerge is an internal variable, do not document
3171 # ui.forcemerge is an internal variable, do not document
3177 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3172 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3178 stats = mergemod.update(repo, ctx.node(), True, True, False,
3173 stats = mergemod.update(repo, ctx.node(), True, True, False,
3179 ctx.p1().node())
3174 ctx.p1().node())
3180 finally:
3175 finally:
3181 repo.ui.setconfig('ui', 'forcemerge', '')
3176 repo.ui.setconfig('ui', 'forcemerge', '')
3182 # report any conflicts
3177 # report any conflicts
3183 if stats and stats[3] > 0:
3178 if stats and stats[3] > 0:
3184 # write out state for --continue
3179 # write out state for --continue
3185 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3180 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3186 repo.opener.write('graftstate', ''.join(nodelines))
3181 repo.opener.write('graftstate', ''.join(nodelines))
3187 raise util.Abort(
3182 raise util.Abort(
3188 _("unresolved conflicts, can't continue"),
3183 _("unresolved conflicts, can't continue"),
3189 hint=_('use hg resolve and hg graft --continue'))
3184 hint=_('use hg resolve and hg graft --continue'))
3190 else:
3185 else:
3191 cont = False
3186 cont = False
3192
3187
3193 # drop the second merge parent
3188 # drop the second merge parent
3194 repo.setparents(current.node(), nullid)
3189 repo.setparents(current.node(), nullid)
3195 repo.dirstate.write()
3190 repo.dirstate.write()
3196 # fix up dirstate for copies and renames
3191 # fix up dirstate for copies and renames
3197 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
3192 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
3198
3193
3199 # commit
3194 # commit
3200 node = repo.commit(text=message, user=user,
3195 node = repo.commit(text=message, user=user,
3201 date=date, extra=extra, editor=editor)
3196 date=date, extra=extra, editor=editor)
3202 if node is None:
3197 if node is None:
3203 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
3198 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
3204 else:
3199 else:
3205 current = repo[node]
3200 current = repo[node]
3206 finally:
3201 finally:
3207 wlock.release()
3202 wlock.release()
3208
3203
3209 # remove state when we complete successfully
3204 # remove state when we complete successfully
3210 if not opts.get('dry_run'):
3205 if not opts.get('dry_run'):
3211 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3206 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3212
3207
3213 return 0
3208 return 0
3214
3209
3215 @command('grep',
3210 @command('grep',
3216 [('0', 'print0', None, _('end fields with NUL')),
3211 [('0', 'print0', None, _('end fields with NUL')),
3217 ('', 'all', None, _('print all revisions that match')),
3212 ('', 'all', None, _('print all revisions that match')),
3218 ('a', 'text', None, _('treat all files as text')),
3213 ('a', 'text', None, _('treat all files as text')),
3219 ('f', 'follow', None,
3214 ('f', 'follow', None,
3220 _('follow changeset history,'
3215 _('follow changeset history,'
3221 ' or file history across copies and renames')),
3216 ' or file history across copies and renames')),
3222 ('i', 'ignore-case', None, _('ignore case when matching')),
3217 ('i', 'ignore-case', None, _('ignore case when matching')),
3223 ('l', 'files-with-matches', None,
3218 ('l', 'files-with-matches', None,
3224 _('print only filenames and revisions that match')),
3219 _('print only filenames and revisions that match')),
3225 ('n', 'line-number', None, _('print matching line numbers')),
3220 ('n', 'line-number', None, _('print matching line numbers')),
3226 ('r', 'rev', [],
3221 ('r', 'rev', [],
3227 _('only search files changed within revision range'), _('REV')),
3222 _('only search files changed within revision range'), _('REV')),
3228 ('u', 'user', None, _('list the author (long with -v)')),
3223 ('u', 'user', None, _('list the author (long with -v)')),
3229 ('d', 'date', None, _('list the date (short with -q)')),
3224 ('d', 'date', None, _('list the date (short with -q)')),
3230 ] + walkopts,
3225 ] + walkopts,
3231 _('[OPTION]... PATTERN [FILE]...'))
3226 _('[OPTION]... PATTERN [FILE]...'))
3232 def grep(ui, repo, pattern, *pats, **opts):
3227 def grep(ui, repo, pattern, *pats, **opts):
3233 """search for a pattern in specified files and revisions
3228 """search for a pattern in specified files and revisions
3234
3229
3235 Search revisions of files for a regular expression.
3230 Search revisions of files for a regular expression.
3236
3231
3237 This command behaves differently than Unix grep. It only accepts
3232 This command behaves differently than Unix grep. It only accepts
3238 Python/Perl regexps. It searches repository history, not the
3233 Python/Perl regexps. It searches repository history, not the
3239 working directory. It always prints the revision number in which a
3234 working directory. It always prints the revision number in which a
3240 match appears.
3235 match appears.
3241
3236
3242 By default, grep only prints output for the first revision of a
3237 By default, grep only prints output for the first revision of a
3243 file in which it finds a match. To get it to print every revision
3238 file in which it finds a match. To get it to print every revision
3244 that contains a change in match status ("-" for a match that
3239 that contains a change in match status ("-" for a match that
3245 becomes a non-match, or "+" for a non-match that becomes a match),
3240 becomes a non-match, or "+" for a non-match that becomes a match),
3246 use the --all flag.
3241 use the --all flag.
3247
3242
3248 Returns 0 if a match is found, 1 otherwise.
3243 Returns 0 if a match is found, 1 otherwise.
3249 """
3244 """
3250 reflags = re.M
3245 reflags = re.M
3251 if opts.get('ignore_case'):
3246 if opts.get('ignore_case'):
3252 reflags |= re.I
3247 reflags |= re.I
3253 try:
3248 try:
3254 regexp = util.compilere(pattern, reflags)
3249 regexp = util.compilere(pattern, reflags)
3255 except re.error, inst:
3250 except re.error, inst:
3256 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3251 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3257 return 1
3252 return 1
3258 sep, eol = ':', '\n'
3253 sep, eol = ':', '\n'
3259 if opts.get('print0'):
3254 if opts.get('print0'):
3260 sep = eol = '\0'
3255 sep = eol = '\0'
3261
3256
3262 getfile = util.lrucachefunc(repo.file)
3257 getfile = util.lrucachefunc(repo.file)
3263
3258
3264 def matchlines(body):
3259 def matchlines(body):
3265 begin = 0
3260 begin = 0
3266 linenum = 0
3261 linenum = 0
3267 while begin < len(body):
3262 while begin < len(body):
3268 match = regexp.search(body, begin)
3263 match = regexp.search(body, begin)
3269 if not match:
3264 if not match:
3270 break
3265 break
3271 mstart, mend = match.span()
3266 mstart, mend = match.span()
3272 linenum += body.count('\n', begin, mstart) + 1
3267 linenum += body.count('\n', begin, mstart) + 1
3273 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3268 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3274 begin = body.find('\n', mend) + 1 or len(body) + 1
3269 begin = body.find('\n', mend) + 1 or len(body) + 1
3275 lend = begin - 1
3270 lend = begin - 1
3276 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3271 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3277
3272
3278 class linestate(object):
3273 class linestate(object):
3279 def __init__(self, line, linenum, colstart, colend):
3274 def __init__(self, line, linenum, colstart, colend):
3280 self.line = line
3275 self.line = line
3281 self.linenum = linenum
3276 self.linenum = linenum
3282 self.colstart = colstart
3277 self.colstart = colstart
3283 self.colend = colend
3278 self.colend = colend
3284
3279
3285 def __hash__(self):
3280 def __hash__(self):
3286 return hash((self.linenum, self.line))
3281 return hash((self.linenum, self.line))
3287
3282
3288 def __eq__(self, other):
3283 def __eq__(self, other):
3289 return self.line == other.line
3284 return self.line == other.line
3290
3285
3291 matches = {}
3286 matches = {}
3292 copies = {}
3287 copies = {}
3293 def grepbody(fn, rev, body):
3288 def grepbody(fn, rev, body):
3294 matches[rev].setdefault(fn, [])
3289 matches[rev].setdefault(fn, [])
3295 m = matches[rev][fn]
3290 m = matches[rev][fn]
3296 for lnum, cstart, cend, line in matchlines(body):
3291 for lnum, cstart, cend, line in matchlines(body):
3297 s = linestate(line, lnum, cstart, cend)
3292 s = linestate(line, lnum, cstart, cend)
3298 m.append(s)
3293 m.append(s)
3299
3294
3300 def difflinestates(a, b):
3295 def difflinestates(a, b):
3301 sm = difflib.SequenceMatcher(None, a, b)
3296 sm = difflib.SequenceMatcher(None, a, b)
3302 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3297 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3303 if tag == 'insert':
3298 if tag == 'insert':
3304 for i in xrange(blo, bhi):
3299 for i in xrange(blo, bhi):
3305 yield ('+', b[i])
3300 yield ('+', b[i])
3306 elif tag == 'delete':
3301 elif tag == 'delete':
3307 for i in xrange(alo, ahi):
3302 for i in xrange(alo, ahi):
3308 yield ('-', a[i])
3303 yield ('-', a[i])
3309 elif tag == 'replace':
3304 elif tag == 'replace':
3310 for i in xrange(alo, ahi):
3305 for i in xrange(alo, ahi):
3311 yield ('-', a[i])
3306 yield ('-', a[i])
3312 for i in xrange(blo, bhi):
3307 for i in xrange(blo, bhi):
3313 yield ('+', b[i])
3308 yield ('+', b[i])
3314
3309
3315 def display(fn, ctx, pstates, states):
3310 def display(fn, ctx, pstates, states):
3316 rev = ctx.rev()
3311 rev = ctx.rev()
3317 datefunc = ui.quiet and util.shortdate or util.datestr
3312 datefunc = ui.quiet and util.shortdate or util.datestr
3318 found = False
3313 found = False
3319 filerevmatches = {}
3314 filerevmatches = {}
3320 def binary():
3315 def binary():
3321 flog = getfile(fn)
3316 flog = getfile(fn)
3322 return util.binary(flog.read(ctx.filenode(fn)))
3317 return util.binary(flog.read(ctx.filenode(fn)))
3323
3318
3324 if opts.get('all'):
3319 if opts.get('all'):
3325 iter = difflinestates(pstates, states)
3320 iter = difflinestates(pstates, states)
3326 else:
3321 else:
3327 iter = [('', l) for l in states]
3322 iter = [('', l) for l in states]
3328 for change, l in iter:
3323 for change, l in iter:
3329 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3324 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3330 before, match, after = None, None, None
3325 before, match, after = None, None, None
3331
3326
3332 if opts.get('line_number'):
3327 if opts.get('line_number'):
3333 cols.append((str(l.linenum), 'grep.linenumber'))
3328 cols.append((str(l.linenum), 'grep.linenumber'))
3334 if opts.get('all'):
3329 if opts.get('all'):
3335 cols.append((change, 'grep.change'))
3330 cols.append((change, 'grep.change'))
3336 if opts.get('user'):
3331 if opts.get('user'):
3337 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3332 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3338 if opts.get('date'):
3333 if opts.get('date'):
3339 cols.append((datefunc(ctx.date()), 'grep.date'))
3334 cols.append((datefunc(ctx.date()), 'grep.date'))
3340 if opts.get('files_with_matches'):
3335 if opts.get('files_with_matches'):
3341 c = (fn, rev)
3336 c = (fn, rev)
3342 if c in filerevmatches:
3337 if c in filerevmatches:
3343 continue
3338 continue
3344 filerevmatches[c] = 1
3339 filerevmatches[c] = 1
3345 else:
3340 else:
3346 before = l.line[:l.colstart]
3341 before = l.line[:l.colstart]
3347 match = l.line[l.colstart:l.colend]
3342 match = l.line[l.colstart:l.colend]
3348 after = l.line[l.colend:]
3343 after = l.line[l.colend:]
3349 for col, label in cols[:-1]:
3344 for col, label in cols[:-1]:
3350 ui.write(col, label=label)
3345 ui.write(col, label=label)
3351 ui.write(sep, label='grep.sep')
3346 ui.write(sep, label='grep.sep')
3352 ui.write(cols[-1][0], label=cols[-1][1])
3347 ui.write(cols[-1][0], label=cols[-1][1])
3353 if before is not None:
3348 if before is not None:
3354 ui.write(sep, label='grep.sep')
3349 ui.write(sep, label='grep.sep')
3355 if not opts.get('text') and binary():
3350 if not opts.get('text') and binary():
3356 ui.write(" Binary file matches")
3351 ui.write(" Binary file matches")
3357 else:
3352 else:
3358 ui.write(before)
3353 ui.write(before)
3359 ui.write(match, label='grep.match')
3354 ui.write(match, label='grep.match')
3360 ui.write(after)
3355 ui.write(after)
3361 ui.write(eol)
3356 ui.write(eol)
3362 found = True
3357 found = True
3363 return found
3358 return found
3364
3359
3365 skip = {}
3360 skip = {}
3366 revfiles = {}
3361 revfiles = {}
3367 matchfn = scmutil.match(repo[None], pats, opts)
3362 matchfn = scmutil.match(repo[None], pats, opts)
3368 found = False
3363 found = False
3369 follow = opts.get('follow')
3364 follow = opts.get('follow')
3370
3365
3371 def prep(ctx, fns):
3366 def prep(ctx, fns):
3372 rev = ctx.rev()
3367 rev = ctx.rev()
3373 pctx = ctx.p1()
3368 pctx = ctx.p1()
3374 parent = pctx.rev()
3369 parent = pctx.rev()
3375 matches.setdefault(rev, {})
3370 matches.setdefault(rev, {})
3376 matches.setdefault(parent, {})
3371 matches.setdefault(parent, {})
3377 files = revfiles.setdefault(rev, [])
3372 files = revfiles.setdefault(rev, [])
3378 for fn in fns:
3373 for fn in fns:
3379 flog = getfile(fn)
3374 flog = getfile(fn)
3380 try:
3375 try:
3381 fnode = ctx.filenode(fn)
3376 fnode = ctx.filenode(fn)
3382 except error.LookupError:
3377 except error.LookupError:
3383 continue
3378 continue
3384
3379
3385 copied = flog.renamed(fnode)
3380 copied = flog.renamed(fnode)
3386 copy = follow and copied and copied[0]
3381 copy = follow and copied and copied[0]
3387 if copy:
3382 if copy:
3388 copies.setdefault(rev, {})[fn] = copy
3383 copies.setdefault(rev, {})[fn] = copy
3389 if fn in skip:
3384 if fn in skip:
3390 if copy:
3385 if copy:
3391 skip[copy] = True
3386 skip[copy] = True
3392 continue
3387 continue
3393 files.append(fn)
3388 files.append(fn)
3394
3389
3395 if fn not in matches[rev]:
3390 if fn not in matches[rev]:
3396 grepbody(fn, rev, flog.read(fnode))
3391 grepbody(fn, rev, flog.read(fnode))
3397
3392
3398 pfn = copy or fn
3393 pfn = copy or fn
3399 if pfn not in matches[parent]:
3394 if pfn not in matches[parent]:
3400 try:
3395 try:
3401 fnode = pctx.filenode(pfn)
3396 fnode = pctx.filenode(pfn)
3402 grepbody(pfn, parent, flog.read(fnode))
3397 grepbody(pfn, parent, flog.read(fnode))
3403 except error.LookupError:
3398 except error.LookupError:
3404 pass
3399 pass
3405
3400
3406 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3401 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3407 rev = ctx.rev()
3402 rev = ctx.rev()
3408 parent = ctx.p1().rev()
3403 parent = ctx.p1().rev()
3409 for fn in sorted(revfiles.get(rev, [])):
3404 for fn in sorted(revfiles.get(rev, [])):
3410 states = matches[rev][fn]
3405 states = matches[rev][fn]
3411 copy = copies.get(rev, {}).get(fn)
3406 copy = copies.get(rev, {}).get(fn)
3412 if fn in skip:
3407 if fn in skip:
3413 if copy:
3408 if copy:
3414 skip[copy] = True
3409 skip[copy] = True
3415 continue
3410 continue
3416 pstates = matches.get(parent, {}).get(copy or fn, [])
3411 pstates = matches.get(parent, {}).get(copy or fn, [])
3417 if pstates or states:
3412 if pstates or states:
3418 r = display(fn, ctx, pstates, states)
3413 r = display(fn, ctx, pstates, states)
3419 found = found or r
3414 found = found or r
3420 if r and not opts.get('all'):
3415 if r and not opts.get('all'):
3421 skip[fn] = True
3416 skip[fn] = True
3422 if copy:
3417 if copy:
3423 skip[copy] = True
3418 skip[copy] = True
3424 del matches[rev]
3419 del matches[rev]
3425 del revfiles[rev]
3420 del revfiles[rev]
3426
3421
3427 return not found
3422 return not found
3428
3423
3429 @command('heads',
3424 @command('heads',
3430 [('r', 'rev', '',
3425 [('r', 'rev', '',
3431 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3426 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3432 ('t', 'topo', False, _('show topological heads only')),
3427 ('t', 'topo', False, _('show topological heads only')),
3433 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3428 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3434 ('c', 'closed', False, _('show normal and closed branch heads')),
3429 ('c', 'closed', False, _('show normal and closed branch heads')),
3435 ] + templateopts,
3430 ] + templateopts,
3436 _('[-ct] [-r STARTREV] [REV]...'))
3431 _('[-ct] [-r STARTREV] [REV]...'))
3437 def heads(ui, repo, *branchrevs, **opts):
3432 def heads(ui, repo, *branchrevs, **opts):
3438 """show branch heads
3433 """show branch heads
3439
3434
3440 With no arguments, show all open branch heads in the repository.
3435 With no arguments, show all open branch heads in the repository.
3441 Branch heads are changesets that have no descendants on the
3436 Branch heads are changesets that have no descendants on the
3442 same branch. They are where development generally takes place and
3437 same branch. They are where development generally takes place and
3443 are the usual targets for update and merge operations.
3438 are the usual targets for update and merge operations.
3444
3439
3445 If one or more REVs are given, only open branch heads on the
3440 If one or more REVs are given, only open branch heads on the
3446 branches associated with the specified changesets are shown. This
3441 branches associated with the specified changesets are shown. This
3447 means that you can use :hg:`heads .` to see the heads on the
3442 means that you can use :hg:`heads .` to see the heads on the
3448 currently checked-out branch.
3443 currently checked-out branch.
3449
3444
3450 If -c/--closed is specified, also show branch heads marked closed
3445 If -c/--closed is specified, also show branch heads marked closed
3451 (see :hg:`commit --close-branch`).
3446 (see :hg:`commit --close-branch`).
3452
3447
3453 If STARTREV is specified, only those heads that are descendants of
3448 If STARTREV is specified, only those heads that are descendants of
3454 STARTREV will be displayed.
3449 STARTREV will be displayed.
3455
3450
3456 If -t/--topo is specified, named branch mechanics will be ignored and only
3451 If -t/--topo is specified, named branch mechanics will be ignored and only
3457 topological heads (changesets with no children) will be shown.
3452 topological heads (changesets with no children) will be shown.
3458
3453
3459 Returns 0 if matching heads are found, 1 if not.
3454 Returns 0 if matching heads are found, 1 if not.
3460 """
3455 """
3461
3456
3462 start = None
3457 start = None
3463 if 'rev' in opts:
3458 if 'rev' in opts:
3464 start = scmutil.revsingle(repo, opts['rev'], None).node()
3459 start = scmutil.revsingle(repo, opts['rev'], None).node()
3465
3460
3466 if opts.get('topo'):
3461 if opts.get('topo'):
3467 heads = [repo[h] for h in repo.heads(start)]
3462 heads = [repo[h] for h in repo.heads(start)]
3468 else:
3463 else:
3469 heads = []
3464 heads = []
3470 for branch in repo.branchmap():
3465 for branch in repo.branchmap():
3471 heads += repo.branchheads(branch, start, opts.get('closed'))
3466 heads += repo.branchheads(branch, start, opts.get('closed'))
3472 heads = [repo[h] for h in heads]
3467 heads = [repo[h] for h in heads]
3473
3468
3474 if branchrevs:
3469 if branchrevs:
3475 branches = set(repo[br].branch() for br in branchrevs)
3470 branches = set(repo[br].branch() for br in branchrevs)
3476 heads = [h for h in heads if h.branch() in branches]
3471 heads = [h for h in heads if h.branch() in branches]
3477
3472
3478 if opts.get('active') and branchrevs:
3473 if opts.get('active') and branchrevs:
3479 dagheads = repo.heads(start)
3474 dagheads = repo.heads(start)
3480 heads = [h for h in heads if h.node() in dagheads]
3475 heads = [h for h in heads if h.node() in dagheads]
3481
3476
3482 if branchrevs:
3477 if branchrevs:
3483 haveheads = set(h.branch() for h in heads)
3478 haveheads = set(h.branch() for h in heads)
3484 if branches - haveheads:
3479 if branches - haveheads:
3485 headless = ', '.join(b for b in branches - haveheads)
3480 headless = ', '.join(b for b in branches - haveheads)
3486 msg = _('no open branch heads found on branches %s')
3481 msg = _('no open branch heads found on branches %s')
3487 if opts.get('rev'):
3482 if opts.get('rev'):
3488 msg += _(' (started at %s)') % opts['rev']
3483 msg += _(' (started at %s)') % opts['rev']
3489 ui.warn((msg + '\n') % headless)
3484 ui.warn((msg + '\n') % headless)
3490
3485
3491 if not heads:
3486 if not heads:
3492 return 1
3487 return 1
3493
3488
3494 heads = sorted(heads, key=lambda x: -x.rev())
3489 heads = sorted(heads, key=lambda x: -x.rev())
3495 displayer = cmdutil.show_changeset(ui, repo, opts)
3490 displayer = cmdutil.show_changeset(ui, repo, opts)
3496 for ctx in heads:
3491 for ctx in heads:
3497 displayer.show(ctx)
3492 displayer.show(ctx)
3498 displayer.close()
3493 displayer.close()
3499
3494
3500 @command('help',
3495 @command('help',
3501 [('e', 'extension', None, _('show only help for extensions')),
3496 [('e', 'extension', None, _('show only help for extensions')),
3502 ('c', 'command', None, _('show only help for commands')),
3497 ('c', 'command', None, _('show only help for commands')),
3503 ('k', 'keyword', '', _('show topics matching keyword')),
3498 ('k', 'keyword', '', _('show topics matching keyword')),
3504 ],
3499 ],
3505 _('[-ec] [TOPIC]'))
3500 _('[-ec] [TOPIC]'))
3506 def help_(ui, name=None, **opts):
3501 def help_(ui, name=None, **opts):
3507 """show help for a given topic or a help overview
3502 """show help for a given topic or a help overview
3508
3503
3509 With no arguments, print a list of commands with short help messages.
3504 With no arguments, print a list of commands with short help messages.
3510
3505
3511 Given a topic, extension, or command name, print help for that
3506 Given a topic, extension, or command name, print help for that
3512 topic.
3507 topic.
3513
3508
3514 Returns 0 if successful.
3509 Returns 0 if successful.
3515 """
3510 """
3516
3511
3517 textwidth = min(ui.termwidth(), 80) - 2
3512 textwidth = min(ui.termwidth(), 80) - 2
3518
3513
3519 keep = ui.verbose and ['verbose'] or []
3514 keep = ui.verbose and ['verbose'] or []
3520 text = help.help_(ui, name, **opts)
3515 text = help.help_(ui, name, **opts)
3521
3516
3522 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3517 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3523 if 'verbose' in pruned:
3518 if 'verbose' in pruned:
3524 keep.append('omitted')
3519 keep.append('omitted')
3525 else:
3520 else:
3526 keep.append('notomitted')
3521 keep.append('notomitted')
3527 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3522 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3528 ui.write(formatted)
3523 ui.write(formatted)
3529
3524
3530
3525
3531 @command('identify|id',
3526 @command('identify|id',
3532 [('r', 'rev', '',
3527 [('r', 'rev', '',
3533 _('identify the specified revision'), _('REV')),
3528 _('identify the specified revision'), _('REV')),
3534 ('n', 'num', None, _('show local revision number')),
3529 ('n', 'num', None, _('show local revision number')),
3535 ('i', 'id', None, _('show global revision id')),
3530 ('i', 'id', None, _('show global revision id')),
3536 ('b', 'branch', None, _('show branch')),
3531 ('b', 'branch', None, _('show branch')),
3537 ('t', 'tags', None, _('show tags')),
3532 ('t', 'tags', None, _('show tags')),
3538 ('B', 'bookmarks', None, _('show bookmarks')),
3533 ('B', 'bookmarks', None, _('show bookmarks')),
3539 ] + remoteopts,
3534 ] + remoteopts,
3540 _('[-nibtB] [-r REV] [SOURCE]'))
3535 _('[-nibtB] [-r REV] [SOURCE]'))
3541 def identify(ui, repo, source=None, rev=None,
3536 def identify(ui, repo, source=None, rev=None,
3542 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3537 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3543 """identify the working copy or specified revision
3538 """identify the working copy or specified revision
3544
3539
3545 Print a summary identifying the repository state at REV using one or
3540 Print a summary identifying the repository state at REV using one or
3546 two parent hash identifiers, followed by a "+" if the working
3541 two parent hash identifiers, followed by a "+" if the working
3547 directory has uncommitted changes, the branch name (if not default),
3542 directory has uncommitted changes, the branch name (if not default),
3548 a list of tags, and a list of bookmarks.
3543 a list of tags, and a list of bookmarks.
3549
3544
3550 When REV is not given, print a summary of the current state of the
3545 When REV is not given, print a summary of the current state of the
3551 repository.
3546 repository.
3552
3547
3553 Specifying a path to a repository root or Mercurial bundle will
3548 Specifying a path to a repository root or Mercurial bundle will
3554 cause lookup to operate on that repository/bundle.
3549 cause lookup to operate on that repository/bundle.
3555
3550
3556 .. container:: verbose
3551 .. container:: verbose
3557
3552
3558 Examples:
3553 Examples:
3559
3554
3560 - generate a build identifier for the working directory::
3555 - generate a build identifier for the working directory::
3561
3556
3562 hg id --id > build-id.dat
3557 hg id --id > build-id.dat
3563
3558
3564 - find the revision corresponding to a tag::
3559 - find the revision corresponding to a tag::
3565
3560
3566 hg id -n -r 1.3
3561 hg id -n -r 1.3
3567
3562
3568 - check the most recent revision of a remote repository::
3563 - check the most recent revision of a remote repository::
3569
3564
3570 hg id -r tip http://selenic.com/hg/
3565 hg id -r tip http://selenic.com/hg/
3571
3566
3572 Returns 0 if successful.
3567 Returns 0 if successful.
3573 """
3568 """
3574
3569
3575 if not repo and not source:
3570 if not repo and not source:
3576 raise util.Abort(_("there is no Mercurial repository here "
3571 raise util.Abort(_("there is no Mercurial repository here "
3577 "(.hg not found)"))
3572 "(.hg not found)"))
3578
3573
3579 hexfunc = ui.debugflag and hex or short
3574 hexfunc = ui.debugflag and hex or short
3580 default = not (num or id or branch or tags or bookmarks)
3575 default = not (num or id or branch or tags or bookmarks)
3581 output = []
3576 output = []
3582 revs = []
3577 revs = []
3583
3578
3584 if source:
3579 if source:
3585 source, branches = hg.parseurl(ui.expandpath(source))
3580 source, branches = hg.parseurl(ui.expandpath(source))
3586 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3581 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3587 repo = peer.local()
3582 repo = peer.local()
3588 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3583 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3589
3584
3590 if not repo:
3585 if not repo:
3591 if num or branch or tags:
3586 if num or branch or tags:
3592 raise util.Abort(
3587 raise util.Abort(
3593 _("can't query remote revision number, branch, or tags"))
3588 _("can't query remote revision number, branch, or tags"))
3594 if not rev and revs:
3589 if not rev and revs:
3595 rev = revs[0]
3590 rev = revs[0]
3596 if not rev:
3591 if not rev:
3597 rev = "tip"
3592 rev = "tip"
3598
3593
3599 remoterev = peer.lookup(rev)
3594 remoterev = peer.lookup(rev)
3600 if default or id:
3595 if default or id:
3601 output = [hexfunc(remoterev)]
3596 output = [hexfunc(remoterev)]
3602
3597
3603 def getbms():
3598 def getbms():
3604 bms = []
3599 bms = []
3605
3600
3606 if 'bookmarks' in peer.listkeys('namespaces'):
3601 if 'bookmarks' in peer.listkeys('namespaces'):
3607 hexremoterev = hex(remoterev)
3602 hexremoterev = hex(remoterev)
3608 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3603 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3609 if bmr == hexremoterev]
3604 if bmr == hexremoterev]
3610
3605
3611 return sorted(bms)
3606 return sorted(bms)
3612
3607
3613 if bookmarks:
3608 if bookmarks:
3614 output.extend(getbms())
3609 output.extend(getbms())
3615 elif default and not ui.quiet:
3610 elif default and not ui.quiet:
3616 # multiple bookmarks for a single parent separated by '/'
3611 # multiple bookmarks for a single parent separated by '/'
3617 bm = '/'.join(getbms())
3612 bm = '/'.join(getbms())
3618 if bm:
3613 if bm:
3619 output.append(bm)
3614 output.append(bm)
3620 else:
3615 else:
3621 if not rev:
3616 if not rev:
3622 ctx = repo[None]
3617 ctx = repo[None]
3623 parents = ctx.parents()
3618 parents = ctx.parents()
3624 changed = ""
3619 changed = ""
3625 if default or id or num:
3620 if default or id or num:
3626 if (util.any(repo.status())
3621 if (util.any(repo.status())
3627 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3622 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3628 changed = '+'
3623 changed = '+'
3629 if default or id:
3624 if default or id:
3630 output = ["%s%s" %
3625 output = ["%s%s" %
3631 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3626 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3632 if num:
3627 if num:
3633 output.append("%s%s" %
3628 output.append("%s%s" %
3634 ('+'.join([str(p.rev()) for p in parents]), changed))
3629 ('+'.join([str(p.rev()) for p in parents]), changed))
3635 else:
3630 else:
3636 ctx = scmutil.revsingle(repo, rev)
3631 ctx = scmutil.revsingle(repo, rev)
3637 if default or id:
3632 if default or id:
3638 output = [hexfunc(ctx.node())]
3633 output = [hexfunc(ctx.node())]
3639 if num:
3634 if num:
3640 output.append(str(ctx.rev()))
3635 output.append(str(ctx.rev()))
3641
3636
3642 if default and not ui.quiet:
3637 if default and not ui.quiet:
3643 b = ctx.branch()
3638 b = ctx.branch()
3644 if b != 'default':
3639 if b != 'default':
3645 output.append("(%s)" % b)
3640 output.append("(%s)" % b)
3646
3641
3647 # multiple tags for a single parent separated by '/'
3642 # multiple tags for a single parent separated by '/'
3648 t = '/'.join(ctx.tags())
3643 t = '/'.join(ctx.tags())
3649 if t:
3644 if t:
3650 output.append(t)
3645 output.append(t)
3651
3646
3652 # multiple bookmarks for a single parent separated by '/'
3647 # multiple bookmarks for a single parent separated by '/'
3653 bm = '/'.join(ctx.bookmarks())
3648 bm = '/'.join(ctx.bookmarks())
3654 if bm:
3649 if bm:
3655 output.append(bm)
3650 output.append(bm)
3656 else:
3651 else:
3657 if branch:
3652 if branch:
3658 output.append(ctx.branch())
3653 output.append(ctx.branch())
3659
3654
3660 if tags:
3655 if tags:
3661 output.extend(ctx.tags())
3656 output.extend(ctx.tags())
3662
3657
3663 if bookmarks:
3658 if bookmarks:
3664 output.extend(ctx.bookmarks())
3659 output.extend(ctx.bookmarks())
3665
3660
3666 ui.write("%s\n" % ' '.join(output))
3661 ui.write("%s\n" % ' '.join(output))
3667
3662
3668 @command('import|patch',
3663 @command('import|patch',
3669 [('p', 'strip', 1,
3664 [('p', 'strip', 1,
3670 _('directory strip option for patch. This has the same '
3665 _('directory strip option for patch. This has the same '
3671 'meaning as the corresponding patch option'), _('NUM')),
3666 'meaning as the corresponding patch option'), _('NUM')),
3672 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3667 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3673 ('e', 'edit', False, _('invoke editor on commit messages')),
3668 ('e', 'edit', False, _('invoke editor on commit messages')),
3674 ('f', 'force', None,
3669 ('f', 'force', None,
3675 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3670 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3676 ('', 'no-commit', None,
3671 ('', 'no-commit', None,
3677 _("don't commit, just update the working directory")),
3672 _("don't commit, just update the working directory")),
3678 ('', 'bypass', None,
3673 ('', 'bypass', None,
3679 _("apply patch without touching the working directory")),
3674 _("apply patch without touching the working directory")),
3680 ('', 'exact', None,
3675 ('', 'exact', None,
3681 _('apply patch to the nodes from which it was generated')),
3676 _('apply patch to the nodes from which it was generated')),
3682 ('', 'import-branch', None,
3677 ('', 'import-branch', None,
3683 _('use any branch information in patch (implied by --exact)'))] +
3678 _('use any branch information in patch (implied by --exact)'))] +
3684 commitopts + commitopts2 + similarityopts,
3679 commitopts + commitopts2 + similarityopts,
3685 _('[OPTION]... PATCH...'))
3680 _('[OPTION]... PATCH...'))
3686 def import_(ui, repo, patch1=None, *patches, **opts):
3681 def import_(ui, repo, patch1=None, *patches, **opts):
3687 """import an ordered set of patches
3682 """import an ordered set of patches
3688
3683
3689 Import a list of patches and commit them individually (unless
3684 Import a list of patches and commit them individually (unless
3690 --no-commit is specified).
3685 --no-commit is specified).
3691
3686
3692 Because import first applies changes to the working directory,
3687 Because import first applies changes to the working directory,
3693 import will abort if there are outstanding changes.
3688 import will abort if there are outstanding changes.
3694
3689
3695 You can import a patch straight from a mail message. Even patches
3690 You can import a patch straight from a mail message. Even patches
3696 as attachments work (to use the body part, it must have type
3691 as attachments work (to use the body part, it must have type
3697 text/plain or text/x-patch). From and Subject headers of email
3692 text/plain or text/x-patch). From and Subject headers of email
3698 message are used as default committer and commit message. All
3693 message are used as default committer and commit message. All
3699 text/plain body parts before first diff are added to commit
3694 text/plain body parts before first diff are added to commit
3700 message.
3695 message.
3701
3696
3702 If the imported patch was generated by :hg:`export`, user and
3697 If the imported patch was generated by :hg:`export`, user and
3703 description from patch override values from message headers and
3698 description from patch override values from message headers and
3704 body. Values given on command line with -m/--message and -u/--user
3699 body. Values given on command line with -m/--message and -u/--user
3705 override these.
3700 override these.
3706
3701
3707 If --exact is specified, import will set the working directory to
3702 If --exact is specified, import will set the working directory to
3708 the parent of each patch before applying it, and will abort if the
3703 the parent of each patch before applying it, and will abort if the
3709 resulting changeset has a different ID than the one recorded in
3704 resulting changeset has a different ID than the one recorded in
3710 the patch. This may happen due to character set problems or other
3705 the patch. This may happen due to character set problems or other
3711 deficiencies in the text patch format.
3706 deficiencies in the text patch format.
3712
3707
3713 Use --bypass to apply and commit patches directly to the
3708 Use --bypass to apply and commit patches directly to the
3714 repository, not touching the working directory. Without --exact,
3709 repository, not touching the working directory. Without --exact,
3715 patches will be applied on top of the working directory parent
3710 patches will be applied on top of the working directory parent
3716 revision.
3711 revision.
3717
3712
3718 With -s/--similarity, hg will attempt to discover renames and
3713 With -s/--similarity, hg will attempt to discover renames and
3719 copies in the patch in the same way as :hg:`addremove`.
3714 copies in the patch in the same way as :hg:`addremove`.
3720
3715
3721 To read a patch from standard input, use "-" as the patch name. If
3716 To read a patch from standard input, use "-" as the patch name. If
3722 a URL is specified, the patch will be downloaded from it.
3717 a URL is specified, the patch will be downloaded from it.
3723 See :hg:`help dates` for a list of formats valid for -d/--date.
3718 See :hg:`help dates` for a list of formats valid for -d/--date.
3724
3719
3725 .. container:: verbose
3720 .. container:: verbose
3726
3721
3727 Examples:
3722 Examples:
3728
3723
3729 - import a traditional patch from a website and detect renames::
3724 - import a traditional patch from a website and detect renames::
3730
3725
3731 hg import -s 80 http://example.com/bugfix.patch
3726 hg import -s 80 http://example.com/bugfix.patch
3732
3727
3733 - import a changeset from an hgweb server::
3728 - import a changeset from an hgweb server::
3734
3729
3735 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3730 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3736
3731
3737 - import all the patches in an Unix-style mbox::
3732 - import all the patches in an Unix-style mbox::
3738
3733
3739 hg import incoming-patches.mbox
3734 hg import incoming-patches.mbox
3740
3735
3741 - attempt to exactly restore an exported changeset (not always
3736 - attempt to exactly restore an exported changeset (not always
3742 possible)::
3737 possible)::
3743
3738
3744 hg import --exact proposed-fix.patch
3739 hg import --exact proposed-fix.patch
3745
3740
3746 Returns 0 on success.
3741 Returns 0 on success.
3747 """
3742 """
3748
3743
3749 if not patch1:
3744 if not patch1:
3750 raise util.Abort(_('need at least one patch to import'))
3745 raise util.Abort(_('need at least one patch to import'))
3751
3746
3752 patches = (patch1,) + patches
3747 patches = (patch1,) + patches
3753
3748
3754 date = opts.get('date')
3749 date = opts.get('date')
3755 if date:
3750 if date:
3756 opts['date'] = util.parsedate(date)
3751 opts['date'] = util.parsedate(date)
3757
3752
3758 update = not opts.get('bypass')
3753 update = not opts.get('bypass')
3759 if not update and opts.get('no_commit'):
3754 if not update and opts.get('no_commit'):
3760 raise util.Abort(_('cannot use --no-commit with --bypass'))
3755 raise util.Abort(_('cannot use --no-commit with --bypass'))
3761 try:
3756 try:
3762 sim = float(opts.get('similarity') or 0)
3757 sim = float(opts.get('similarity') or 0)
3763 except ValueError:
3758 except ValueError:
3764 raise util.Abort(_('similarity must be a number'))
3759 raise util.Abort(_('similarity must be a number'))
3765 if sim < 0 or sim > 100:
3760 if sim < 0 or sim > 100:
3766 raise util.Abort(_('similarity must be between 0 and 100'))
3761 raise util.Abort(_('similarity must be between 0 and 100'))
3767 if sim and not update:
3762 if sim and not update:
3768 raise util.Abort(_('cannot use --similarity with --bypass'))
3763 raise util.Abort(_('cannot use --similarity with --bypass'))
3769
3764
3770 if update:
3765 if update:
3771 cmdutil.checkunfinished(repo)
3766 cmdutil.checkunfinished(repo)
3772 if (opts.get('exact') or not opts.get('force')) and update:
3767 if (opts.get('exact') or not opts.get('force')) and update:
3773 cmdutil.bailifchanged(repo)
3768 cmdutil.bailifchanged(repo)
3774
3769
3775 base = opts["base"]
3770 base = opts["base"]
3776 wlock = lock = tr = None
3771 wlock = lock = tr = None
3777 msgs = []
3772 msgs = []
3778
3773
3779
3774
3780 try:
3775 try:
3781 try:
3776 try:
3782 wlock = repo.wlock()
3777 wlock = repo.wlock()
3783 if not opts.get('no_commit'):
3778 if not opts.get('no_commit'):
3784 lock = repo.lock()
3779 lock = repo.lock()
3785 tr = repo.transaction('import')
3780 tr = repo.transaction('import')
3786 parents = repo.parents()
3781 parents = repo.parents()
3787 for patchurl in patches:
3782 for patchurl in patches:
3788 if patchurl == '-':
3783 if patchurl == '-':
3789 ui.status(_('applying patch from stdin\n'))
3784 ui.status(_('applying patch from stdin\n'))
3790 patchfile = ui.fin
3785 patchfile = ui.fin
3791 patchurl = 'stdin' # for error message
3786 patchurl = 'stdin' # for error message
3792 else:
3787 else:
3793 patchurl = os.path.join(base, patchurl)
3788 patchurl = os.path.join(base, patchurl)
3794 ui.status(_('applying %s\n') % patchurl)
3789 ui.status(_('applying %s\n') % patchurl)
3795 patchfile = hg.openpath(ui, patchurl)
3790 patchfile = hg.openpath(ui, patchurl)
3796
3791
3797 haspatch = False
3792 haspatch = False
3798 for hunk in patch.split(patchfile):
3793 for hunk in patch.split(patchfile):
3799 (msg, node) = cmdutil.tryimportone(ui, repo, hunk, parents,
3794 (msg, node) = cmdutil.tryimportone(ui, repo, hunk, parents,
3800 opts, msgs, hg.clean)
3795 opts, msgs, hg.clean)
3801 if msg:
3796 if msg:
3802 haspatch = True
3797 haspatch = True
3803 ui.note(msg + '\n')
3798 ui.note(msg + '\n')
3804 if update or opts.get('exact'):
3799 if update or opts.get('exact'):
3805 parents = repo.parents()
3800 parents = repo.parents()
3806 else:
3801 else:
3807 parents = [repo[node]]
3802 parents = [repo[node]]
3808
3803
3809 if not haspatch:
3804 if not haspatch:
3810 raise util.Abort(_('%s: no diffs found') % patchurl)
3805 raise util.Abort(_('%s: no diffs found') % patchurl)
3811
3806
3812 if tr:
3807 if tr:
3813 tr.close()
3808 tr.close()
3814 if msgs:
3809 if msgs:
3815 repo.savecommitmessage('\n* * *\n'.join(msgs))
3810 repo.savecommitmessage('\n* * *\n'.join(msgs))
3816 except: # re-raises
3811 except: # re-raises
3817 # wlock.release() indirectly calls dirstate.write(): since
3812 # wlock.release() indirectly calls dirstate.write(): since
3818 # we're crashing, we do not want to change the working dir
3813 # we're crashing, we do not want to change the working dir
3819 # parent after all, so make sure it writes nothing
3814 # parent after all, so make sure it writes nothing
3820 repo.dirstate.invalidate()
3815 repo.dirstate.invalidate()
3821 raise
3816 raise
3822 finally:
3817 finally:
3823 if tr:
3818 if tr:
3824 tr.release()
3819 tr.release()
3825 release(lock, wlock)
3820 release(lock, wlock)
3826
3821
3827 @command('incoming|in',
3822 @command('incoming|in',
3828 [('f', 'force', None,
3823 [('f', 'force', None,
3829 _('run even if remote repository is unrelated')),
3824 _('run even if remote repository is unrelated')),
3830 ('n', 'newest-first', None, _('show newest record first')),
3825 ('n', 'newest-first', None, _('show newest record first')),
3831 ('', 'bundle', '',
3826 ('', 'bundle', '',
3832 _('file to store the bundles into'), _('FILE')),
3827 _('file to store the bundles into'), _('FILE')),
3833 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3828 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3834 ('B', 'bookmarks', False, _("compare bookmarks")),
3829 ('B', 'bookmarks', False, _("compare bookmarks")),
3835 ('b', 'branch', [],
3830 ('b', 'branch', [],
3836 _('a specific branch you would like to pull'), _('BRANCH')),
3831 _('a specific branch you would like to pull'), _('BRANCH')),
3837 ] + logopts + remoteopts + subrepoopts,
3832 ] + logopts + remoteopts + subrepoopts,
3838 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3833 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3839 def incoming(ui, repo, source="default", **opts):
3834 def incoming(ui, repo, source="default", **opts):
3840 """show new changesets found in source
3835 """show new changesets found in source
3841
3836
3842 Show new changesets found in the specified path/URL or the default
3837 Show new changesets found in the specified path/URL or the default
3843 pull location. These are the changesets that would have been pulled
3838 pull location. These are the changesets that would have been pulled
3844 if a pull at the time you issued this command.
3839 if a pull at the time you issued this command.
3845
3840
3846 For remote repository, using --bundle avoids downloading the
3841 For remote repository, using --bundle avoids downloading the
3847 changesets twice if the incoming is followed by a pull.
3842 changesets twice if the incoming is followed by a pull.
3848
3843
3849 See pull for valid source format details.
3844 See pull for valid source format details.
3850
3845
3851 Returns 0 if there are incoming changes, 1 otherwise.
3846 Returns 0 if there are incoming changes, 1 otherwise.
3852 """
3847 """
3853 if opts.get('graph'):
3848 if opts.get('graph'):
3854 cmdutil.checkunsupportedgraphflags([], opts)
3849 cmdutil.checkunsupportedgraphflags([], opts)
3855 def display(other, chlist, displayer):
3850 def display(other, chlist, displayer):
3856 revdag = cmdutil.graphrevs(other, chlist, opts)
3851 revdag = cmdutil.graphrevs(other, chlist, opts)
3857 showparents = [ctx.node() for ctx in repo[None].parents()]
3852 showparents = [ctx.node() for ctx in repo[None].parents()]
3858 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3853 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3859 graphmod.asciiedges)
3854 graphmod.asciiedges)
3860
3855
3861 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3856 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3862 return 0
3857 return 0
3863
3858
3864 if opts.get('bundle') and opts.get('subrepos'):
3859 if opts.get('bundle') and opts.get('subrepos'):
3865 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3860 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3866
3861
3867 if opts.get('bookmarks'):
3862 if opts.get('bookmarks'):
3868 source, branches = hg.parseurl(ui.expandpath(source),
3863 source, branches = hg.parseurl(ui.expandpath(source),
3869 opts.get('branch'))
3864 opts.get('branch'))
3870 other = hg.peer(repo, opts, source)
3865 other = hg.peer(repo, opts, source)
3871 if 'bookmarks' not in other.listkeys('namespaces'):
3866 if 'bookmarks' not in other.listkeys('namespaces'):
3872 ui.warn(_("remote doesn't support bookmarks\n"))
3867 ui.warn(_("remote doesn't support bookmarks\n"))
3873 return 0
3868 return 0
3874 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3869 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3875 return bookmarks.diff(ui, repo, other)
3870 return bookmarks.diff(ui, repo, other)
3876
3871
3877 repo._subtoppath = ui.expandpath(source)
3872 repo._subtoppath = ui.expandpath(source)
3878 try:
3873 try:
3879 return hg.incoming(ui, repo, source, opts)
3874 return hg.incoming(ui, repo, source, opts)
3880 finally:
3875 finally:
3881 del repo._subtoppath
3876 del repo._subtoppath
3882
3877
3883
3878
3884 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3879 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3885 def init(ui, dest=".", **opts):
3880 def init(ui, dest=".", **opts):
3886 """create a new repository in the given directory
3881 """create a new repository in the given directory
3887
3882
3888 Initialize a new repository in the given directory. If the given
3883 Initialize a new repository in the given directory. If the given
3889 directory does not exist, it will be created.
3884 directory does not exist, it will be created.
3890
3885
3891 If no directory is given, the current directory is used.
3886 If no directory is given, the current directory is used.
3892
3887
3893 It is possible to specify an ``ssh://`` URL as the destination.
3888 It is possible to specify an ``ssh://`` URL as the destination.
3894 See :hg:`help urls` for more information.
3889 See :hg:`help urls` for more information.
3895
3890
3896 Returns 0 on success.
3891 Returns 0 on success.
3897 """
3892 """
3898 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3893 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3899
3894
3900 @command('locate',
3895 @command('locate',
3901 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3896 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3902 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3897 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3903 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3898 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3904 ] + walkopts,
3899 ] + walkopts,
3905 _('[OPTION]... [PATTERN]...'))
3900 _('[OPTION]... [PATTERN]...'))
3906 def locate(ui, repo, *pats, **opts):
3901 def locate(ui, repo, *pats, **opts):
3907 """locate files matching specific patterns
3902 """locate files matching specific patterns
3908
3903
3909 Print files under Mercurial control in the working directory whose
3904 Print files under Mercurial control in the working directory whose
3910 names match the given patterns.
3905 names match the given patterns.
3911
3906
3912 By default, this command searches all directories in the working
3907 By default, this command searches all directories in the working
3913 directory. To search just the current directory and its
3908 directory. To search just the current directory and its
3914 subdirectories, use "--include .".
3909 subdirectories, use "--include .".
3915
3910
3916 If no patterns are given to match, this command prints the names
3911 If no patterns are given to match, this command prints the names
3917 of all files under Mercurial control in the working directory.
3912 of all files under Mercurial control in the working directory.
3918
3913
3919 If you want to feed the output of this command into the "xargs"
3914 If you want to feed the output of this command into the "xargs"
3920 command, use the -0 option to both this command and "xargs". This
3915 command, use the -0 option to both this command and "xargs". This
3921 will avoid the problem of "xargs" treating single filenames that
3916 will avoid the problem of "xargs" treating single filenames that
3922 contain whitespace as multiple filenames.
3917 contain whitespace as multiple filenames.
3923
3918
3924 Returns 0 if a match is found, 1 otherwise.
3919 Returns 0 if a match is found, 1 otherwise.
3925 """
3920 """
3926 end = opts.get('print0') and '\0' or '\n'
3921 end = opts.get('print0') and '\0' or '\n'
3927 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3922 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3928
3923
3929 ret = 1
3924 ret = 1
3930 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3925 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3931 m.bad = lambda x, y: False
3926 m.bad = lambda x, y: False
3932 for abs in repo[rev].walk(m):
3927 for abs in repo[rev].walk(m):
3933 if not rev and abs not in repo.dirstate:
3928 if not rev and abs not in repo.dirstate:
3934 continue
3929 continue
3935 if opts.get('fullpath'):
3930 if opts.get('fullpath'):
3936 ui.write(repo.wjoin(abs), end)
3931 ui.write(repo.wjoin(abs), end)
3937 else:
3932 else:
3938 ui.write(((pats and m.rel(abs)) or abs), end)
3933 ui.write(((pats and m.rel(abs)) or abs), end)
3939 ret = 0
3934 ret = 0
3940
3935
3941 return ret
3936 return ret
3942
3937
3943 @command('^log|history',
3938 @command('^log|history',
3944 [('f', 'follow', None,
3939 [('f', 'follow', None,
3945 _('follow changeset history, or file history across copies and renames')),
3940 _('follow changeset history, or file history across copies and renames')),
3946 ('', 'follow-first', None,
3941 ('', 'follow-first', None,
3947 _('only follow the first parent of merge changesets (DEPRECATED)')),
3942 _('only follow the first parent of merge changesets (DEPRECATED)')),
3948 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3943 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3949 ('C', 'copies', None, _('show copied files')),
3944 ('C', 'copies', None, _('show copied files')),
3950 ('k', 'keyword', [],
3945 ('k', 'keyword', [],
3951 _('do case-insensitive search for a given text'), _('TEXT')),
3946 _('do case-insensitive search for a given text'), _('TEXT')),
3952 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3947 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3953 ('', 'removed', None, _('include revisions where files were removed')),
3948 ('', 'removed', None, _('include revisions where files were removed')),
3954 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3949 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3955 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3950 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3956 ('', 'only-branch', [],
3951 ('', 'only-branch', [],
3957 _('show only changesets within the given named branch (DEPRECATED)'),
3952 _('show only changesets within the given named branch (DEPRECATED)'),
3958 _('BRANCH')),
3953 _('BRANCH')),
3959 ('b', 'branch', [],
3954 ('b', 'branch', [],
3960 _('show changesets within the given named branch'), _('BRANCH')),
3955 _('show changesets within the given named branch'), _('BRANCH')),
3961 ('P', 'prune', [],
3956 ('P', 'prune', [],
3962 _('do not display revision or any of its ancestors'), _('REV')),
3957 _('do not display revision or any of its ancestors'), _('REV')),
3963 ] + logopts + walkopts,
3958 ] + logopts + walkopts,
3964 _('[OPTION]... [FILE]'))
3959 _('[OPTION]... [FILE]'))
3965 def log(ui, repo, *pats, **opts):
3960 def log(ui, repo, *pats, **opts):
3966 """show revision history of entire repository or files
3961 """show revision history of entire repository or files
3967
3962
3968 Print the revision history of the specified files or the entire
3963 Print the revision history of the specified files or the entire
3969 project.
3964 project.
3970
3965
3971 If no revision range is specified, the default is ``tip:0`` unless
3966 If no revision range is specified, the default is ``tip:0`` unless
3972 --follow is set, in which case the working directory parent is
3967 --follow is set, in which case the working directory parent is
3973 used as the starting revision.
3968 used as the starting revision.
3974
3969
3975 File history is shown without following rename or copy history of
3970 File history is shown without following rename or copy history of
3976 files. Use -f/--follow with a filename to follow history across
3971 files. Use -f/--follow with a filename to follow history across
3977 renames and copies. --follow without a filename will only show
3972 renames and copies. --follow without a filename will only show
3978 ancestors or descendants of the starting revision.
3973 ancestors or descendants of the starting revision.
3979
3974
3980 By default this command prints revision number and changeset id,
3975 By default this command prints revision number and changeset id,
3981 tags, non-trivial parents, user, date and time, and a summary for
3976 tags, non-trivial parents, user, date and time, and a summary for
3982 each commit. When the -v/--verbose switch is used, the list of
3977 each commit. When the -v/--verbose switch is used, the list of
3983 changed files and full commit message are shown.
3978 changed files and full commit message are shown.
3984
3979
3985 With --graph the revisions are shown as an ASCII art DAG with the most
3980 With --graph the revisions are shown as an ASCII art DAG with the most
3986 recent changeset at the top.
3981 recent changeset at the top.
3987 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
3982 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
3988 and '+' represents a fork where the changeset from the lines below is a
3983 and '+' represents a fork where the changeset from the lines below is a
3989 parent of the 'o' merge on the same same line.
3984 parent of the 'o' merge on the same same line.
3990
3985
3991 .. note::
3986 .. note::
3992
3987
3993 log -p/--patch may generate unexpected diff output for merge
3988 log -p/--patch may generate unexpected diff output for merge
3994 changesets, as it will only compare the merge changeset against
3989 changesets, as it will only compare the merge changeset against
3995 its first parent. Also, only files different from BOTH parents
3990 its first parent. Also, only files different from BOTH parents
3996 will appear in files:.
3991 will appear in files:.
3997
3992
3998 .. note::
3993 .. note::
3999
3994
4000 for performance reasons, log FILE may omit duplicate changes
3995 for performance reasons, log FILE may omit duplicate changes
4001 made on branches and will not show deletions. To see all
3996 made on branches and will not show deletions. To see all
4002 changes including duplicates and deletions, use the --removed
3997 changes including duplicates and deletions, use the --removed
4003 switch.
3998 switch.
4004
3999
4005 .. container:: verbose
4000 .. container:: verbose
4006
4001
4007 Some examples:
4002 Some examples:
4008
4003
4009 - changesets with full descriptions and file lists::
4004 - changesets with full descriptions and file lists::
4010
4005
4011 hg log -v
4006 hg log -v
4012
4007
4013 - changesets ancestral to the working directory::
4008 - changesets ancestral to the working directory::
4014
4009
4015 hg log -f
4010 hg log -f
4016
4011
4017 - last 10 commits on the current branch::
4012 - last 10 commits on the current branch::
4018
4013
4019 hg log -l 10 -b .
4014 hg log -l 10 -b .
4020
4015
4021 - changesets showing all modifications of a file, including removals::
4016 - changesets showing all modifications of a file, including removals::
4022
4017
4023 hg log --removed file.c
4018 hg log --removed file.c
4024
4019
4025 - all changesets that touch a directory, with diffs, excluding merges::
4020 - all changesets that touch a directory, with diffs, excluding merges::
4026
4021
4027 hg log -Mp lib/
4022 hg log -Mp lib/
4028
4023
4029 - all revision numbers that match a keyword::
4024 - all revision numbers that match a keyword::
4030
4025
4031 hg log -k bug --template "{rev}\\n"
4026 hg log -k bug --template "{rev}\\n"
4032
4027
4033 - check if a given changeset is included is a tagged release::
4028 - check if a given changeset is included is a tagged release::
4034
4029
4035 hg log -r "a21ccf and ancestor(1.9)"
4030 hg log -r "a21ccf and ancestor(1.9)"
4036
4031
4037 - find all changesets by some user in a date range::
4032 - find all changesets by some user in a date range::
4038
4033
4039 hg log -k alice -d "may 2008 to jul 2008"
4034 hg log -k alice -d "may 2008 to jul 2008"
4040
4035
4041 - summary of all changesets after the last tag::
4036 - summary of all changesets after the last tag::
4042
4037
4043 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4038 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4044
4039
4045 See :hg:`help dates` for a list of formats valid for -d/--date.
4040 See :hg:`help dates` for a list of formats valid for -d/--date.
4046
4041
4047 See :hg:`help revisions` and :hg:`help revsets` for more about
4042 See :hg:`help revisions` and :hg:`help revsets` for more about
4048 specifying revisions.
4043 specifying revisions.
4049
4044
4050 See :hg:`help templates` for more about pre-packaged styles and
4045 See :hg:`help templates` for more about pre-packaged styles and
4051 specifying custom templates.
4046 specifying custom templates.
4052
4047
4053 Returns 0 on success.
4048 Returns 0 on success.
4054 """
4049 """
4055 if opts.get('graph'):
4050 if opts.get('graph'):
4056 return cmdutil.graphlog(ui, repo, *pats, **opts)
4051 return cmdutil.graphlog(ui, repo, *pats, **opts)
4057
4052
4058 matchfn = scmutil.match(repo[None], pats, opts)
4053 matchfn = scmutil.match(repo[None], pats, opts)
4059 limit = cmdutil.loglimit(opts)
4054 limit = cmdutil.loglimit(opts)
4060 count = 0
4055 count = 0
4061
4056
4062 getrenamed, endrev = None, None
4057 getrenamed, endrev = None, None
4063 if opts.get('copies'):
4058 if opts.get('copies'):
4064 if opts.get('rev'):
4059 if opts.get('rev'):
4065 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4060 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4066 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4061 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4067
4062
4068 df = False
4063 df = False
4069 if opts.get("date"):
4064 if opts.get("date"):
4070 df = util.matchdate(opts["date"])
4065 df = util.matchdate(opts["date"])
4071
4066
4072 branches = opts.get('branch', []) + opts.get('only_branch', [])
4067 branches = opts.get('branch', []) + opts.get('only_branch', [])
4073 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4068 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4074
4069
4075 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4070 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4076 def prep(ctx, fns):
4071 def prep(ctx, fns):
4077 rev = ctx.rev()
4072 rev = ctx.rev()
4078 parents = [p for p in repo.changelog.parentrevs(rev)
4073 parents = [p for p in repo.changelog.parentrevs(rev)
4079 if p != nullrev]
4074 if p != nullrev]
4080 if opts.get('no_merges') and len(parents) == 2:
4075 if opts.get('no_merges') and len(parents) == 2:
4081 return
4076 return
4082 if opts.get('only_merges') and len(parents) != 2:
4077 if opts.get('only_merges') and len(parents) != 2:
4083 return
4078 return
4084 if opts.get('branch') and ctx.branch() not in opts['branch']:
4079 if opts.get('branch') and ctx.branch() not in opts['branch']:
4085 return
4080 return
4086 if df and not df(ctx.date()[0]):
4081 if df and not df(ctx.date()[0]):
4087 return
4082 return
4088
4083
4089 lower = encoding.lower
4084 lower = encoding.lower
4090 if opts.get('user'):
4085 if opts.get('user'):
4091 luser = lower(ctx.user())
4086 luser = lower(ctx.user())
4092 for k in [lower(x) for x in opts['user']]:
4087 for k in [lower(x) for x in opts['user']]:
4093 if (k in luser):
4088 if (k in luser):
4094 break
4089 break
4095 else:
4090 else:
4096 return
4091 return
4097 if opts.get('keyword'):
4092 if opts.get('keyword'):
4098 luser = lower(ctx.user())
4093 luser = lower(ctx.user())
4099 ldesc = lower(ctx.description())
4094 ldesc = lower(ctx.description())
4100 lfiles = lower(" ".join(ctx.files()))
4095 lfiles = lower(" ".join(ctx.files()))
4101 for k in [lower(x) for x in opts['keyword']]:
4096 for k in [lower(x) for x in opts['keyword']]:
4102 if (k in luser or k in ldesc or k in lfiles):
4097 if (k in luser or k in ldesc or k in lfiles):
4103 break
4098 break
4104 else:
4099 else:
4105 return
4100 return
4106
4101
4107 copies = None
4102 copies = None
4108 if getrenamed is not None and rev:
4103 if getrenamed is not None and rev:
4109 copies = []
4104 copies = []
4110 for fn in ctx.files():
4105 for fn in ctx.files():
4111 rename = getrenamed(fn, rev)
4106 rename = getrenamed(fn, rev)
4112 if rename:
4107 if rename:
4113 copies.append((fn, rename[0]))
4108 copies.append((fn, rename[0]))
4114
4109
4115 revmatchfn = None
4110 revmatchfn = None
4116 if opts.get('patch') or opts.get('stat'):
4111 if opts.get('patch') or opts.get('stat'):
4117 if opts.get('follow') or opts.get('follow_first'):
4112 if opts.get('follow') or opts.get('follow_first'):
4118 # note: this might be wrong when following through merges
4113 # note: this might be wrong when following through merges
4119 revmatchfn = scmutil.match(repo[None], fns, default='path')
4114 revmatchfn = scmutil.match(repo[None], fns, default='path')
4120 else:
4115 else:
4121 revmatchfn = matchfn
4116 revmatchfn = matchfn
4122
4117
4123 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4118 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4124
4119
4125 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4120 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4126 if displayer.flush(ctx.rev()):
4121 if displayer.flush(ctx.rev()):
4127 count += 1
4122 count += 1
4128 if count == limit:
4123 if count == limit:
4129 break
4124 break
4130 displayer.close()
4125 displayer.close()
4131
4126
4132 @command('manifest',
4127 @command('manifest',
4133 [('r', 'rev', '', _('revision to display'), _('REV')),
4128 [('r', 'rev', '', _('revision to display'), _('REV')),
4134 ('', 'all', False, _("list files from all revisions"))],
4129 ('', 'all', False, _("list files from all revisions"))],
4135 _('[-r REV]'))
4130 _('[-r REV]'))
4136 def manifest(ui, repo, node=None, rev=None, **opts):
4131 def manifest(ui, repo, node=None, rev=None, **opts):
4137 """output the current or given revision of the project manifest
4132 """output the current or given revision of the project manifest
4138
4133
4139 Print a list of version controlled files for the given revision.
4134 Print a list of version controlled files for the given revision.
4140 If no revision is given, the first parent of the working directory
4135 If no revision is given, the first parent of the working directory
4141 is used, or the null revision if no revision is checked out.
4136 is used, or the null revision if no revision is checked out.
4142
4137
4143 With -v, print file permissions, symlink and executable bits.
4138 With -v, print file permissions, symlink and executable bits.
4144 With --debug, print file revision hashes.
4139 With --debug, print file revision hashes.
4145
4140
4146 If option --all is specified, the list of all files from all revisions
4141 If option --all is specified, the list of all files from all revisions
4147 is printed. This includes deleted and renamed files.
4142 is printed. This includes deleted and renamed files.
4148
4143
4149 Returns 0 on success.
4144 Returns 0 on success.
4150 """
4145 """
4151
4146
4152 fm = ui.formatter('manifest', opts)
4147 fm = ui.formatter('manifest', opts)
4153
4148
4154 if opts.get('all'):
4149 if opts.get('all'):
4155 if rev or node:
4150 if rev or node:
4156 raise util.Abort(_("can't specify a revision with --all"))
4151 raise util.Abort(_("can't specify a revision with --all"))
4157
4152
4158 res = []
4153 res = []
4159 prefix = "data/"
4154 prefix = "data/"
4160 suffix = ".i"
4155 suffix = ".i"
4161 plen = len(prefix)
4156 plen = len(prefix)
4162 slen = len(suffix)
4157 slen = len(suffix)
4163 lock = repo.lock()
4158 lock = repo.lock()
4164 try:
4159 try:
4165 for fn, b, size in repo.store.datafiles():
4160 for fn, b, size in repo.store.datafiles():
4166 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4161 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4167 res.append(fn[plen:-slen])
4162 res.append(fn[plen:-slen])
4168 finally:
4163 finally:
4169 lock.release()
4164 lock.release()
4170 for f in res:
4165 for f in res:
4171 fm.startitem()
4166 fm.startitem()
4172 fm.write("path", '%s\n', f)
4167 fm.write("path", '%s\n', f)
4173 fm.end()
4168 fm.end()
4174 return
4169 return
4175
4170
4176 if rev and node:
4171 if rev and node:
4177 raise util.Abort(_("please specify just one revision"))
4172 raise util.Abort(_("please specify just one revision"))
4178
4173
4179 if not node:
4174 if not node:
4180 node = rev
4175 node = rev
4181
4176
4182 char = {'l': '@', 'x': '*', '': ''}
4177 char = {'l': '@', 'x': '*', '': ''}
4183 mode = {'l': '644', 'x': '755', '': '644'}
4178 mode = {'l': '644', 'x': '755', '': '644'}
4184 ctx = scmutil.revsingle(repo, node)
4179 ctx = scmutil.revsingle(repo, node)
4185 mf = ctx.manifest()
4180 mf = ctx.manifest()
4186 for f in ctx:
4181 for f in ctx:
4187 fm.startitem()
4182 fm.startitem()
4188 fl = ctx[f].flags()
4183 fl = ctx[f].flags()
4189 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4184 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4190 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4185 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4191 fm.write('path', '%s\n', f)
4186 fm.write('path', '%s\n', f)
4192 fm.end()
4187 fm.end()
4193
4188
4194 @command('^merge',
4189 @command('^merge',
4195 [('f', 'force', None,
4190 [('f', 'force', None,
4196 _('force a merge including outstanding changes (DEPRECATED)')),
4191 _('force a merge including outstanding changes (DEPRECATED)')),
4197 ('r', 'rev', '', _('revision to merge'), _('REV')),
4192 ('r', 'rev', '', _('revision to merge'), _('REV')),
4198 ('P', 'preview', None,
4193 ('P', 'preview', None,
4199 _('review revisions to merge (no merge is performed)'))
4194 _('review revisions to merge (no merge is performed)'))
4200 ] + mergetoolopts,
4195 ] + mergetoolopts,
4201 _('[-P] [-f] [[-r] REV]'))
4196 _('[-P] [-f] [[-r] REV]'))
4202 def merge(ui, repo, node=None, **opts):
4197 def merge(ui, repo, node=None, **opts):
4203 """merge working directory with another revision
4198 """merge working directory with another revision
4204
4199
4205 The current working directory is updated with all changes made in
4200 The current working directory is updated with all changes made in
4206 the requested revision since the last common predecessor revision.
4201 the requested revision since the last common predecessor revision.
4207
4202
4208 Files that changed between either parent are marked as changed for
4203 Files that changed between either parent are marked as changed for
4209 the next commit and a commit must be performed before any further
4204 the next commit and a commit must be performed before any further
4210 updates to the repository are allowed. The next commit will have
4205 updates to the repository are allowed. The next commit will have
4211 two parents.
4206 two parents.
4212
4207
4213 ``--tool`` can be used to specify the merge tool used for file
4208 ``--tool`` can be used to specify the merge tool used for file
4214 merges. It overrides the HGMERGE environment variable and your
4209 merges. It overrides the HGMERGE environment variable and your
4215 configuration files. See :hg:`help merge-tools` for options.
4210 configuration files. See :hg:`help merge-tools` for options.
4216
4211
4217 If no revision is specified, the working directory's parent is a
4212 If no revision is specified, the working directory's parent is a
4218 head revision, and the current branch contains exactly one other
4213 head revision, and the current branch contains exactly one other
4219 head, the other head is merged with by default. Otherwise, an
4214 head, the other head is merged with by default. Otherwise, an
4220 explicit revision with which to merge with must be provided.
4215 explicit revision with which to merge with must be provided.
4221
4216
4222 :hg:`resolve` must be used to resolve unresolved files.
4217 :hg:`resolve` must be used to resolve unresolved files.
4223
4218
4224 To undo an uncommitted merge, use :hg:`update --clean .` which
4219 To undo an uncommitted merge, use :hg:`update --clean .` which
4225 will check out a clean copy of the original merge parent, losing
4220 will check out a clean copy of the original merge parent, losing
4226 all changes.
4221 all changes.
4227
4222
4228 Returns 0 on success, 1 if there are unresolved files.
4223 Returns 0 on success, 1 if there are unresolved files.
4229 """
4224 """
4230
4225
4231 if opts.get('rev') and node:
4226 if opts.get('rev') and node:
4232 raise util.Abort(_("please specify just one revision"))
4227 raise util.Abort(_("please specify just one revision"))
4233 if not node:
4228 if not node:
4234 node = opts.get('rev')
4229 node = opts.get('rev')
4235
4230
4236 if node:
4231 if node:
4237 node = scmutil.revsingle(repo, node).node()
4232 node = scmutil.revsingle(repo, node).node()
4238
4233
4239 if not node and repo._bookmarkcurrent:
4234 if not node and repo._bookmarkcurrent:
4240 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4235 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4241 curhead = repo[repo._bookmarkcurrent].node()
4236 curhead = repo[repo._bookmarkcurrent].node()
4242 if len(bmheads) == 2:
4237 if len(bmheads) == 2:
4243 if curhead == bmheads[0]:
4238 if curhead == bmheads[0]:
4244 node = bmheads[1]
4239 node = bmheads[1]
4245 else:
4240 else:
4246 node = bmheads[0]
4241 node = bmheads[0]
4247 elif len(bmheads) > 2:
4242 elif len(bmheads) > 2:
4248 raise util.Abort(_("multiple matching bookmarks to merge - "
4243 raise util.Abort(_("multiple matching bookmarks to merge - "
4249 "please merge with an explicit rev or bookmark"),
4244 "please merge with an explicit rev or bookmark"),
4250 hint=_("run 'hg heads' to see all heads"))
4245 hint=_("run 'hg heads' to see all heads"))
4251 elif len(bmheads) <= 1:
4246 elif len(bmheads) <= 1:
4252 raise util.Abort(_("no matching bookmark to merge - "
4247 raise util.Abort(_("no matching bookmark to merge - "
4253 "please merge with an explicit rev or bookmark"),
4248 "please merge with an explicit rev or bookmark"),
4254 hint=_("run 'hg heads' to see all heads"))
4249 hint=_("run 'hg heads' to see all heads"))
4255
4250
4256 if not node and not repo._bookmarkcurrent:
4251 if not node and not repo._bookmarkcurrent:
4257 branch = repo[None].branch()
4252 branch = repo[None].branch()
4258 bheads = repo.branchheads(branch)
4253 bheads = repo.branchheads(branch)
4259 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4254 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4260
4255
4261 if len(nbhs) > 2:
4256 if len(nbhs) > 2:
4262 raise util.Abort(_("branch '%s' has %d heads - "
4257 raise util.Abort(_("branch '%s' has %d heads - "
4263 "please merge with an explicit rev")
4258 "please merge with an explicit rev")
4264 % (branch, len(bheads)),
4259 % (branch, len(bheads)),
4265 hint=_("run 'hg heads .' to see heads"))
4260 hint=_("run 'hg heads .' to see heads"))
4266
4261
4267 parent = repo.dirstate.p1()
4262 parent = repo.dirstate.p1()
4268 if len(nbhs) <= 1:
4263 if len(nbhs) <= 1:
4269 if len(bheads) > 1:
4264 if len(bheads) > 1:
4270 raise util.Abort(_("heads are bookmarked - "
4265 raise util.Abort(_("heads are bookmarked - "
4271 "please merge with an explicit rev"),
4266 "please merge with an explicit rev"),
4272 hint=_("run 'hg heads' to see all heads"))
4267 hint=_("run 'hg heads' to see all heads"))
4273 if len(repo.heads()) > 1:
4268 if len(repo.heads()) > 1:
4274 raise util.Abort(_("branch '%s' has one head - "
4269 raise util.Abort(_("branch '%s' has one head - "
4275 "please merge with an explicit rev")
4270 "please merge with an explicit rev")
4276 % branch,
4271 % branch,
4277 hint=_("run 'hg heads' to see all heads"))
4272 hint=_("run 'hg heads' to see all heads"))
4278 msg, hint = _('nothing to merge'), None
4273 msg, hint = _('nothing to merge'), None
4279 if parent != repo.lookup(branch):
4274 if parent != repo.lookup(branch):
4280 hint = _("use 'hg update' instead")
4275 hint = _("use 'hg update' instead")
4281 raise util.Abort(msg, hint=hint)
4276 raise util.Abort(msg, hint=hint)
4282
4277
4283 if parent not in bheads:
4278 if parent not in bheads:
4284 raise util.Abort(_('working directory not at a head revision'),
4279 raise util.Abort(_('working directory not at a head revision'),
4285 hint=_("use 'hg update' or merge with an "
4280 hint=_("use 'hg update' or merge with an "
4286 "explicit revision"))
4281 "explicit revision"))
4287 if parent == nbhs[0]:
4282 if parent == nbhs[0]:
4288 node = nbhs[-1]
4283 node = nbhs[-1]
4289 else:
4284 else:
4290 node = nbhs[0]
4285 node = nbhs[0]
4291
4286
4292 if opts.get('preview'):
4287 if opts.get('preview'):
4293 # find nodes that are ancestors of p2 but not of p1
4288 # find nodes that are ancestors of p2 but not of p1
4294 p1 = repo.lookup('.')
4289 p1 = repo.lookup('.')
4295 p2 = repo.lookup(node)
4290 p2 = repo.lookup(node)
4296 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4291 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4297
4292
4298 displayer = cmdutil.show_changeset(ui, repo, opts)
4293 displayer = cmdutil.show_changeset(ui, repo, opts)
4299 for node in nodes:
4294 for node in nodes:
4300 displayer.show(repo[node])
4295 displayer.show(repo[node])
4301 displayer.close()
4296 displayer.close()
4302 return 0
4297 return 0
4303
4298
4304 try:
4299 try:
4305 # ui.forcemerge is an internal variable, do not document
4300 # ui.forcemerge is an internal variable, do not document
4306 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4301 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4307 return hg.merge(repo, node, force=opts.get('force'))
4302 return hg.merge(repo, node, force=opts.get('force'))
4308 finally:
4303 finally:
4309 ui.setconfig('ui', 'forcemerge', '')
4304 ui.setconfig('ui', 'forcemerge', '')
4310
4305
4311 @command('outgoing|out',
4306 @command('outgoing|out',
4312 [('f', 'force', None, _('run even when the destination is unrelated')),
4307 [('f', 'force', None, _('run even when the destination is unrelated')),
4313 ('r', 'rev', [],
4308 ('r', 'rev', [],
4314 _('a changeset intended to be included in the destination'), _('REV')),
4309 _('a changeset intended to be included in the destination'), _('REV')),
4315 ('n', 'newest-first', None, _('show newest record first')),
4310 ('n', 'newest-first', None, _('show newest record first')),
4316 ('B', 'bookmarks', False, _('compare bookmarks')),
4311 ('B', 'bookmarks', False, _('compare bookmarks')),
4317 ('b', 'branch', [], _('a specific branch you would like to push'),
4312 ('b', 'branch', [], _('a specific branch you would like to push'),
4318 _('BRANCH')),
4313 _('BRANCH')),
4319 ] + logopts + remoteopts + subrepoopts,
4314 ] + logopts + remoteopts + subrepoopts,
4320 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4315 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4321 def outgoing(ui, repo, dest=None, **opts):
4316 def outgoing(ui, repo, dest=None, **opts):
4322 """show changesets not found in the destination
4317 """show changesets not found in the destination
4323
4318
4324 Show changesets not found in the specified destination repository
4319 Show changesets not found in the specified destination repository
4325 or the default push location. These are the changesets that would
4320 or the default push location. These are the changesets that would
4326 be pushed if a push was requested.
4321 be pushed if a push was requested.
4327
4322
4328 See pull for details of valid destination formats.
4323 See pull for details of valid destination formats.
4329
4324
4330 Returns 0 if there are outgoing changes, 1 otherwise.
4325 Returns 0 if there are outgoing changes, 1 otherwise.
4331 """
4326 """
4332 if opts.get('graph'):
4327 if opts.get('graph'):
4333 cmdutil.checkunsupportedgraphflags([], opts)
4328 cmdutil.checkunsupportedgraphflags([], opts)
4334 o = hg._outgoing(ui, repo, dest, opts)
4329 o = hg._outgoing(ui, repo, dest, opts)
4335 if o is None:
4330 if o is None:
4336 return
4331 return
4337
4332
4338 revdag = cmdutil.graphrevs(repo, o, opts)
4333 revdag = cmdutil.graphrevs(repo, o, opts)
4339 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4334 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4340 showparents = [ctx.node() for ctx in repo[None].parents()]
4335 showparents = [ctx.node() for ctx in repo[None].parents()]
4341 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4336 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4342 graphmod.asciiedges)
4337 graphmod.asciiedges)
4343 return 0
4338 return 0
4344
4339
4345 if opts.get('bookmarks'):
4340 if opts.get('bookmarks'):
4346 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4341 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4347 dest, branches = hg.parseurl(dest, opts.get('branch'))
4342 dest, branches = hg.parseurl(dest, opts.get('branch'))
4348 other = hg.peer(repo, opts, dest)
4343 other = hg.peer(repo, opts, dest)
4349 if 'bookmarks' not in other.listkeys('namespaces'):
4344 if 'bookmarks' not in other.listkeys('namespaces'):
4350 ui.warn(_("remote doesn't support bookmarks\n"))
4345 ui.warn(_("remote doesn't support bookmarks\n"))
4351 return 0
4346 return 0
4352 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4347 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4353 return bookmarks.diff(ui, other, repo)
4348 return bookmarks.diff(ui, other, repo)
4354
4349
4355 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4350 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4356 try:
4351 try:
4357 return hg.outgoing(ui, repo, dest, opts)
4352 return hg.outgoing(ui, repo, dest, opts)
4358 finally:
4353 finally:
4359 del repo._subtoppath
4354 del repo._subtoppath
4360
4355
4361 @command('parents',
4356 @command('parents',
4362 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4357 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4363 ] + templateopts,
4358 ] + templateopts,
4364 _('[-r REV] [FILE]'))
4359 _('[-r REV] [FILE]'))
4365 def parents(ui, repo, file_=None, **opts):
4360 def parents(ui, repo, file_=None, **opts):
4366 """show the parents of the working directory or revision
4361 """show the parents of the working directory or revision
4367
4362
4368 Print the working directory's parent revisions. If a revision is
4363 Print the working directory's parent revisions. If a revision is
4369 given via -r/--rev, the parent of that revision will be printed.
4364 given via -r/--rev, the parent of that revision will be printed.
4370 If a file argument is given, the revision in which the file was
4365 If a file argument is given, the revision in which the file was
4371 last changed (before the working directory revision or the
4366 last changed (before the working directory revision or the
4372 argument to --rev if given) is printed.
4367 argument to --rev if given) is printed.
4373
4368
4374 Returns 0 on success.
4369 Returns 0 on success.
4375 """
4370 """
4376
4371
4377 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4372 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4378
4373
4379 if file_:
4374 if file_:
4380 m = scmutil.match(ctx, (file_,), opts)
4375 m = scmutil.match(ctx, (file_,), opts)
4381 if m.anypats() or len(m.files()) != 1:
4376 if m.anypats() or len(m.files()) != 1:
4382 raise util.Abort(_('can only specify an explicit filename'))
4377 raise util.Abort(_('can only specify an explicit filename'))
4383 file_ = m.files()[0]
4378 file_ = m.files()[0]
4384 filenodes = []
4379 filenodes = []
4385 for cp in ctx.parents():
4380 for cp in ctx.parents():
4386 if not cp:
4381 if not cp:
4387 continue
4382 continue
4388 try:
4383 try:
4389 filenodes.append(cp.filenode(file_))
4384 filenodes.append(cp.filenode(file_))
4390 except error.LookupError:
4385 except error.LookupError:
4391 pass
4386 pass
4392 if not filenodes:
4387 if not filenodes:
4393 raise util.Abort(_("'%s' not found in manifest!") % file_)
4388 raise util.Abort(_("'%s' not found in manifest!") % file_)
4394 p = []
4389 p = []
4395 for fn in filenodes:
4390 for fn in filenodes:
4396 fctx = repo.filectx(file_, fileid=fn)
4391 fctx = repo.filectx(file_, fileid=fn)
4397 p.append(fctx.node())
4392 p.append(fctx.node())
4398 else:
4393 else:
4399 p = [cp.node() for cp in ctx.parents()]
4394 p = [cp.node() for cp in ctx.parents()]
4400
4395
4401 displayer = cmdutil.show_changeset(ui, repo, opts)
4396 displayer = cmdutil.show_changeset(ui, repo, opts)
4402 for n in p:
4397 for n in p:
4403 if n != nullid:
4398 if n != nullid:
4404 displayer.show(repo[n])
4399 displayer.show(repo[n])
4405 displayer.close()
4400 displayer.close()
4406
4401
4407 @command('paths', [], _('[NAME]'))
4402 @command('paths', [], _('[NAME]'))
4408 def paths(ui, repo, search=None):
4403 def paths(ui, repo, search=None):
4409 """show aliases for remote repositories
4404 """show aliases for remote repositories
4410
4405
4411 Show definition of symbolic path name NAME. If no name is given,
4406 Show definition of symbolic path name NAME. If no name is given,
4412 show definition of all available names.
4407 show definition of all available names.
4413
4408
4414 Option -q/--quiet suppresses all output when searching for NAME
4409 Option -q/--quiet suppresses all output when searching for NAME
4415 and shows only the path names when listing all definitions.
4410 and shows only the path names when listing all definitions.
4416
4411
4417 Path names are defined in the [paths] section of your
4412 Path names are defined in the [paths] section of your
4418 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4413 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4419 repository, ``.hg/hgrc`` is used, too.
4414 repository, ``.hg/hgrc`` is used, too.
4420
4415
4421 The path names ``default`` and ``default-push`` have a special
4416 The path names ``default`` and ``default-push`` have a special
4422 meaning. When performing a push or pull operation, they are used
4417 meaning. When performing a push or pull operation, they are used
4423 as fallbacks if no location is specified on the command-line.
4418 as fallbacks if no location is specified on the command-line.
4424 When ``default-push`` is set, it will be used for push and
4419 When ``default-push`` is set, it will be used for push and
4425 ``default`` will be used for pull; otherwise ``default`` is used
4420 ``default`` will be used for pull; otherwise ``default`` is used
4426 as the fallback for both. When cloning a repository, the clone
4421 as the fallback for both. When cloning a repository, the clone
4427 source is written as ``default`` in ``.hg/hgrc``. Note that
4422 source is written as ``default`` in ``.hg/hgrc``. Note that
4428 ``default`` and ``default-push`` apply to all inbound (e.g.
4423 ``default`` and ``default-push`` apply to all inbound (e.g.
4429 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4424 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4430 :hg:`bundle`) operations.
4425 :hg:`bundle`) operations.
4431
4426
4432 See :hg:`help urls` for more information.
4427 See :hg:`help urls` for more information.
4433
4428
4434 Returns 0 on success.
4429 Returns 0 on success.
4435 """
4430 """
4436 if search:
4431 if search:
4437 for name, path in ui.configitems("paths"):
4432 for name, path in ui.configitems("paths"):
4438 if name == search:
4433 if name == search:
4439 ui.status("%s\n" % util.hidepassword(path))
4434 ui.status("%s\n" % util.hidepassword(path))
4440 return
4435 return
4441 if not ui.quiet:
4436 if not ui.quiet:
4442 ui.warn(_("not found!\n"))
4437 ui.warn(_("not found!\n"))
4443 return 1
4438 return 1
4444 else:
4439 else:
4445 for name, path in ui.configitems("paths"):
4440 for name, path in ui.configitems("paths"):
4446 if ui.quiet:
4441 if ui.quiet:
4447 ui.write("%s\n" % name)
4442 ui.write("%s\n" % name)
4448 else:
4443 else:
4449 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4444 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4450
4445
4451 @command('phase',
4446 @command('phase',
4452 [('p', 'public', False, _('set changeset phase to public')),
4447 [('p', 'public', False, _('set changeset phase to public')),
4453 ('d', 'draft', False, _('set changeset phase to draft')),
4448 ('d', 'draft', False, _('set changeset phase to draft')),
4454 ('s', 'secret', False, _('set changeset phase to secret')),
4449 ('s', 'secret', False, _('set changeset phase to secret')),
4455 ('f', 'force', False, _('allow to move boundary backward')),
4450 ('f', 'force', False, _('allow to move boundary backward')),
4456 ('r', 'rev', [], _('target revision'), _('REV')),
4451 ('r', 'rev', [], _('target revision'), _('REV')),
4457 ],
4452 ],
4458 _('[-p|-d|-s] [-f] [-r] REV...'))
4453 _('[-p|-d|-s] [-f] [-r] REV...'))
4459 def phase(ui, repo, *revs, **opts):
4454 def phase(ui, repo, *revs, **opts):
4460 """set or show the current phase name
4455 """set or show the current phase name
4461
4456
4462 With no argument, show the phase name of specified revisions.
4457 With no argument, show the phase name of specified revisions.
4463
4458
4464 With one of -p/--public, -d/--draft or -s/--secret, change the
4459 With one of -p/--public, -d/--draft or -s/--secret, change the
4465 phase value of the specified revisions.
4460 phase value of the specified revisions.
4466
4461
4467 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4462 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4468 lower phase to an higher phase. Phases are ordered as follows::
4463 lower phase to an higher phase. Phases are ordered as follows::
4469
4464
4470 public < draft < secret
4465 public < draft < secret
4471
4466
4472 Returns 0 on success, 1 if no phases were changed or some could not
4467 Returns 0 on success, 1 if no phases were changed or some could not
4473 be changed.
4468 be changed.
4474 """
4469 """
4475 # search for a unique phase argument
4470 # search for a unique phase argument
4476 targetphase = None
4471 targetphase = None
4477 for idx, name in enumerate(phases.phasenames):
4472 for idx, name in enumerate(phases.phasenames):
4478 if opts[name]:
4473 if opts[name]:
4479 if targetphase is not None:
4474 if targetphase is not None:
4480 raise util.Abort(_('only one phase can be specified'))
4475 raise util.Abort(_('only one phase can be specified'))
4481 targetphase = idx
4476 targetphase = idx
4482
4477
4483 # look for specified revision
4478 # look for specified revision
4484 revs = list(revs)
4479 revs = list(revs)
4485 revs.extend(opts['rev'])
4480 revs.extend(opts['rev'])
4486 if not revs:
4481 if not revs:
4487 raise util.Abort(_('no revisions specified'))
4482 raise util.Abort(_('no revisions specified'))
4488
4483
4489 revs = scmutil.revrange(repo, revs)
4484 revs = scmutil.revrange(repo, revs)
4490
4485
4491 lock = None
4486 lock = None
4492 ret = 0
4487 ret = 0
4493 if targetphase is None:
4488 if targetphase is None:
4494 # display
4489 # display
4495 for r in revs:
4490 for r in revs:
4496 ctx = repo[r]
4491 ctx = repo[r]
4497 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4492 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4498 else:
4493 else:
4499 lock = repo.lock()
4494 lock = repo.lock()
4500 try:
4495 try:
4501 # set phase
4496 # set phase
4502 if not revs:
4497 if not revs:
4503 raise util.Abort(_('empty revision set'))
4498 raise util.Abort(_('empty revision set'))
4504 nodes = [repo[r].node() for r in revs]
4499 nodes = [repo[r].node() for r in revs]
4505 olddata = repo._phasecache.getphaserevs(repo)[:]
4500 olddata = repo._phasecache.getphaserevs(repo)[:]
4506 phases.advanceboundary(repo, targetphase, nodes)
4501 phases.advanceboundary(repo, targetphase, nodes)
4507 if opts['force']:
4502 if opts['force']:
4508 phases.retractboundary(repo, targetphase, nodes)
4503 phases.retractboundary(repo, targetphase, nodes)
4509 finally:
4504 finally:
4510 lock.release()
4505 lock.release()
4511 # moving revision from public to draft may hide them
4506 # moving revision from public to draft may hide them
4512 # We have to check result on an unfiltered repository
4507 # We have to check result on an unfiltered repository
4513 unfi = repo.unfiltered()
4508 unfi = repo.unfiltered()
4514 newdata = repo._phasecache.getphaserevs(unfi)
4509 newdata = repo._phasecache.getphaserevs(unfi)
4515 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4510 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4516 cl = unfi.changelog
4511 cl = unfi.changelog
4517 rejected = [n for n in nodes
4512 rejected = [n for n in nodes
4518 if newdata[cl.rev(n)] < targetphase]
4513 if newdata[cl.rev(n)] < targetphase]
4519 if rejected:
4514 if rejected:
4520 ui.warn(_('cannot move %i changesets to a higher '
4515 ui.warn(_('cannot move %i changesets to a higher '
4521 'phase, use --force\n') % len(rejected))
4516 'phase, use --force\n') % len(rejected))
4522 ret = 1
4517 ret = 1
4523 if changes:
4518 if changes:
4524 msg = _('phase changed for %i changesets\n') % changes
4519 msg = _('phase changed for %i changesets\n') % changes
4525 if ret:
4520 if ret:
4526 ui.status(msg)
4521 ui.status(msg)
4527 else:
4522 else:
4528 ui.note(msg)
4523 ui.note(msg)
4529 else:
4524 else:
4530 ui.warn(_('no phases changed\n'))
4525 ui.warn(_('no phases changed\n'))
4531 ret = 1
4526 ret = 1
4532 return ret
4527 return ret
4533
4528
4534 def postincoming(ui, repo, modheads, optupdate, checkout):
4529 def postincoming(ui, repo, modheads, optupdate, checkout):
4535 if modheads == 0:
4530 if modheads == 0:
4536 return
4531 return
4537 if optupdate:
4532 if optupdate:
4538 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
4533 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
4539 try:
4534 try:
4540 ret = hg.update(repo, checkout)
4535 ret = hg.update(repo, checkout)
4541 except util.Abort, inst:
4536 except util.Abort, inst:
4542 ui.warn(_("not updating: %s\n") % str(inst))
4537 ui.warn(_("not updating: %s\n") % str(inst))
4543 if inst.hint:
4538 if inst.hint:
4544 ui.warn(_("(%s)\n") % inst.hint)
4539 ui.warn(_("(%s)\n") % inst.hint)
4545 return 0
4540 return 0
4546 if not ret and not checkout:
4541 if not ret and not checkout:
4547 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4542 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4548 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4543 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4549 return ret
4544 return ret
4550 if modheads > 1:
4545 if modheads > 1:
4551 currentbranchheads = len(repo.branchheads())
4546 currentbranchheads = len(repo.branchheads())
4552 if currentbranchheads == modheads:
4547 if currentbranchheads == modheads:
4553 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4548 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4554 elif currentbranchheads > 1:
4549 elif currentbranchheads > 1:
4555 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4550 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4556 "merge)\n"))
4551 "merge)\n"))
4557 else:
4552 else:
4558 ui.status(_("(run 'hg heads' to see heads)\n"))
4553 ui.status(_("(run 'hg heads' to see heads)\n"))
4559 else:
4554 else:
4560 ui.status(_("(run 'hg update' to get a working copy)\n"))
4555 ui.status(_("(run 'hg update' to get a working copy)\n"))
4561
4556
4562 @command('^pull',
4557 @command('^pull',
4563 [('u', 'update', None,
4558 [('u', 'update', None,
4564 _('update to new branch head if changesets were pulled')),
4559 _('update to new branch head if changesets were pulled')),
4565 ('f', 'force', None, _('run even when remote repository is unrelated')),
4560 ('f', 'force', None, _('run even when remote repository is unrelated')),
4566 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4561 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4567 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4562 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4568 ('b', 'branch', [], _('a specific branch you would like to pull'),
4563 ('b', 'branch', [], _('a specific branch you would like to pull'),
4569 _('BRANCH')),
4564 _('BRANCH')),
4570 ] + remoteopts,
4565 ] + remoteopts,
4571 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4566 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4572 def pull(ui, repo, source="default", **opts):
4567 def pull(ui, repo, source="default", **opts):
4573 """pull changes from the specified source
4568 """pull changes from the specified source
4574
4569
4575 Pull changes from a remote repository to a local one.
4570 Pull changes from a remote repository to a local one.
4576
4571
4577 This finds all changes from the repository at the specified path
4572 This finds all changes from the repository at the specified path
4578 or URL and adds them to a local repository (the current one unless
4573 or URL and adds them to a local repository (the current one unless
4579 -R is specified). By default, this does not update the copy of the
4574 -R is specified). By default, this does not update the copy of the
4580 project in the working directory.
4575 project in the working directory.
4581
4576
4582 Use :hg:`incoming` if you want to see what would have been added
4577 Use :hg:`incoming` if you want to see what would have been added
4583 by a pull at the time you issued this command. If you then decide
4578 by a pull at the time you issued this command. If you then decide
4584 to add those changes to the repository, you should use :hg:`pull
4579 to add those changes to the repository, you should use :hg:`pull
4585 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4580 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4586
4581
4587 If SOURCE is omitted, the 'default' path will be used.
4582 If SOURCE is omitted, the 'default' path will be used.
4588 See :hg:`help urls` for more information.
4583 See :hg:`help urls` for more information.
4589
4584
4590 Returns 0 on success, 1 if an update had unresolved files.
4585 Returns 0 on success, 1 if an update had unresolved files.
4591 """
4586 """
4592 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4587 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4593 other = hg.peer(repo, opts, source)
4588 other = hg.peer(repo, opts, source)
4594 try:
4589 try:
4595 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4590 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4596 revs, checkout = hg.addbranchrevs(repo, other, branches,
4591 revs, checkout = hg.addbranchrevs(repo, other, branches,
4597 opts.get('rev'))
4592 opts.get('rev'))
4598
4593
4599 remotebookmarks = other.listkeys('bookmarks')
4594 remotebookmarks = other.listkeys('bookmarks')
4600
4595
4601 if opts.get('bookmark'):
4596 if opts.get('bookmark'):
4602 if not revs:
4597 if not revs:
4603 revs = []
4598 revs = []
4604 for b in opts['bookmark']:
4599 for b in opts['bookmark']:
4605 if b not in remotebookmarks:
4600 if b not in remotebookmarks:
4606 raise util.Abort(_('remote bookmark %s not found!') % b)
4601 raise util.Abort(_('remote bookmark %s not found!') % b)
4607 revs.append(remotebookmarks[b])
4602 revs.append(remotebookmarks[b])
4608
4603
4609 if revs:
4604 if revs:
4610 try:
4605 try:
4611 revs = [other.lookup(rev) for rev in revs]
4606 revs = [other.lookup(rev) for rev in revs]
4612 except error.CapabilityError:
4607 except error.CapabilityError:
4613 err = _("other repository doesn't support revision lookup, "
4608 err = _("other repository doesn't support revision lookup, "
4614 "so a rev cannot be specified.")
4609 "so a rev cannot be specified.")
4615 raise util.Abort(err)
4610 raise util.Abort(err)
4616
4611
4617 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4612 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4618 bookmarks.updatefromremote(ui, repo, remotebookmarks, source)
4613 bookmarks.updatefromremote(ui, repo, remotebookmarks, source)
4619 if checkout:
4614 if checkout:
4620 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4615 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4621 repo._subtoppath = source
4616 repo._subtoppath = source
4622 try:
4617 try:
4623 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4618 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4624
4619
4625 finally:
4620 finally:
4626 del repo._subtoppath
4621 del repo._subtoppath
4627
4622
4628 # update specified bookmarks
4623 # update specified bookmarks
4629 if opts.get('bookmark'):
4624 if opts.get('bookmark'):
4630 marks = repo._bookmarks
4625 marks = repo._bookmarks
4631 for b in opts['bookmark']:
4626 for b in opts['bookmark']:
4632 # explicit pull overrides local bookmark if any
4627 # explicit pull overrides local bookmark if any
4633 ui.status(_("importing bookmark %s\n") % b)
4628 ui.status(_("importing bookmark %s\n") % b)
4634 marks[b] = repo[remotebookmarks[b]].node()
4629 marks[b] = repo[remotebookmarks[b]].node()
4635 marks.write()
4630 marks.write()
4636 finally:
4631 finally:
4637 other.close()
4632 other.close()
4638 return ret
4633 return ret
4639
4634
4640 @command('^push',
4635 @command('^push',
4641 [('f', 'force', None, _('force push')),
4636 [('f', 'force', None, _('force push')),
4642 ('r', 'rev', [],
4637 ('r', 'rev', [],
4643 _('a changeset intended to be included in the destination'),
4638 _('a changeset intended to be included in the destination'),
4644 _('REV')),
4639 _('REV')),
4645 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4640 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4646 ('b', 'branch', [],
4641 ('b', 'branch', [],
4647 _('a specific branch you would like to push'), _('BRANCH')),
4642 _('a specific branch you would like to push'), _('BRANCH')),
4648 ('', 'new-branch', False, _('allow pushing a new branch')),
4643 ('', 'new-branch', False, _('allow pushing a new branch')),
4649 ] + remoteopts,
4644 ] + remoteopts,
4650 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4645 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4651 def push(ui, repo, dest=None, **opts):
4646 def push(ui, repo, dest=None, **opts):
4652 """push changes to the specified destination
4647 """push changes to the specified destination
4653
4648
4654 Push changesets from the local repository to the specified
4649 Push changesets from the local repository to the specified
4655 destination.
4650 destination.
4656
4651
4657 This operation is symmetrical to pull: it is identical to a pull
4652 This operation is symmetrical to pull: it is identical to a pull
4658 in the destination repository from the current one.
4653 in the destination repository from the current one.
4659
4654
4660 By default, push will not allow creation of new heads at the
4655 By default, push will not allow creation of new heads at the
4661 destination, since multiple heads would make it unclear which head
4656 destination, since multiple heads would make it unclear which head
4662 to use. In this situation, it is recommended to pull and merge
4657 to use. In this situation, it is recommended to pull and merge
4663 before pushing.
4658 before pushing.
4664
4659
4665 Use --new-branch if you want to allow push to create a new named
4660 Use --new-branch if you want to allow push to create a new named
4666 branch that is not present at the destination. This allows you to
4661 branch that is not present at the destination. This allows you to
4667 only create a new branch without forcing other changes.
4662 only create a new branch without forcing other changes.
4668
4663
4669 .. note::
4664 .. note::
4670
4665
4671 Extra care should be taken with the -f/--force option,
4666 Extra care should be taken with the -f/--force option,
4672 which will push all new heads on all branches, an action which will
4667 which will push all new heads on all branches, an action which will
4673 almost always cause confusion for collaborators.
4668 almost always cause confusion for collaborators.
4674
4669
4675 If -r/--rev is used, the specified revision and all its ancestors
4670 If -r/--rev is used, the specified revision and all its ancestors
4676 will be pushed to the remote repository.
4671 will be pushed to the remote repository.
4677
4672
4678 If -B/--bookmark is used, the specified bookmarked revision, its
4673 If -B/--bookmark is used, the specified bookmarked revision, its
4679 ancestors, and the bookmark will be pushed to the remote
4674 ancestors, and the bookmark will be pushed to the remote
4680 repository.
4675 repository.
4681
4676
4682 Please see :hg:`help urls` for important details about ``ssh://``
4677 Please see :hg:`help urls` for important details about ``ssh://``
4683 URLs. If DESTINATION is omitted, a default path will be used.
4678 URLs. If DESTINATION is omitted, a default path will be used.
4684
4679
4685 Returns 0 if push was successful, 1 if nothing to push.
4680 Returns 0 if push was successful, 1 if nothing to push.
4686 """
4681 """
4687
4682
4688 if opts.get('bookmark'):
4683 if opts.get('bookmark'):
4689 ui.setconfig('bookmarks', 'pushing', opts['bookmark'])
4684 ui.setconfig('bookmarks', 'pushing', opts['bookmark'])
4690 for b in opts['bookmark']:
4685 for b in opts['bookmark']:
4691 # translate -B options to -r so changesets get pushed
4686 # translate -B options to -r so changesets get pushed
4692 if b in repo._bookmarks:
4687 if b in repo._bookmarks:
4693 opts.setdefault('rev', []).append(b)
4688 opts.setdefault('rev', []).append(b)
4694 else:
4689 else:
4695 # if we try to push a deleted bookmark, translate it to null
4690 # if we try to push a deleted bookmark, translate it to null
4696 # this lets simultaneous -r, -b options continue working
4691 # this lets simultaneous -r, -b options continue working
4697 opts.setdefault('rev', []).append("null")
4692 opts.setdefault('rev', []).append("null")
4698
4693
4699 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4694 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4700 dest, branches = hg.parseurl(dest, opts.get('branch'))
4695 dest, branches = hg.parseurl(dest, opts.get('branch'))
4701 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4696 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4702 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4697 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4703 try:
4698 try:
4704 other = hg.peer(repo, opts, dest)
4699 other = hg.peer(repo, opts, dest)
4705 except error.RepoError:
4700 except error.RepoError:
4706 if dest == "default-push":
4701 if dest == "default-push":
4707 raise util.Abort(_("default repository not configured!"),
4702 raise util.Abort(_("default repository not configured!"),
4708 hint=_('see the "path" section in "hg help config"'))
4703 hint=_('see the "path" section in "hg help config"'))
4709 else:
4704 else:
4710 raise
4705 raise
4711
4706
4712 if revs:
4707 if revs:
4713 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4708 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4714
4709
4715 repo._subtoppath = dest
4710 repo._subtoppath = dest
4716 try:
4711 try:
4717 # push subrepos depth-first for coherent ordering
4712 # push subrepos depth-first for coherent ordering
4718 c = repo['']
4713 c = repo['']
4719 subs = c.substate # only repos that are committed
4714 subs = c.substate # only repos that are committed
4720 for s in sorted(subs):
4715 for s in sorted(subs):
4721 if c.sub(s).push(opts) == 0:
4716 if c.sub(s).push(opts) == 0:
4722 return False
4717 return False
4723 finally:
4718 finally:
4724 del repo._subtoppath
4719 del repo._subtoppath
4725 result = repo.push(other, opts.get('force'), revs=revs,
4720 result = repo.push(other, opts.get('force'), revs=revs,
4726 newbranch=opts.get('new_branch'))
4721 newbranch=opts.get('new_branch'))
4727
4722
4728 result = not result
4723 result = not result
4729
4724
4730 if opts.get('bookmark'):
4725 if opts.get('bookmark'):
4731 bresult = bookmarks.pushtoremote(ui, repo, other, opts['bookmark'])
4726 bresult = bookmarks.pushtoremote(ui, repo, other, opts['bookmark'])
4732 if bresult == 2:
4727 if bresult == 2:
4733 return 2
4728 return 2
4734 if not result and bresult:
4729 if not result and bresult:
4735 result = 2
4730 result = 2
4736
4731
4737 return result
4732 return result
4738
4733
4739 @command('recover', [])
4734 @command('recover', [])
4740 def recover(ui, repo):
4735 def recover(ui, repo):
4741 """roll back an interrupted transaction
4736 """roll back an interrupted transaction
4742
4737
4743 Recover from an interrupted commit or pull.
4738 Recover from an interrupted commit or pull.
4744
4739
4745 This command tries to fix the repository status after an
4740 This command tries to fix the repository status after an
4746 interrupted operation. It should only be necessary when Mercurial
4741 interrupted operation. It should only be necessary when Mercurial
4747 suggests it.
4742 suggests it.
4748
4743
4749 Returns 0 if successful, 1 if nothing to recover or verify fails.
4744 Returns 0 if successful, 1 if nothing to recover or verify fails.
4750 """
4745 """
4751 if repo.recover():
4746 if repo.recover():
4752 return hg.verify(repo)
4747 return hg.verify(repo)
4753 return 1
4748 return 1
4754
4749
4755 @command('^remove|rm',
4750 @command('^remove|rm',
4756 [('A', 'after', None, _('record delete for missing files')),
4751 [('A', 'after', None, _('record delete for missing files')),
4757 ('f', 'force', None,
4752 ('f', 'force', None,
4758 _('remove (and delete) file even if added or modified')),
4753 _('remove (and delete) file even if added or modified')),
4759 ] + walkopts,
4754 ] + walkopts,
4760 _('[OPTION]... FILE...'))
4755 _('[OPTION]... FILE...'))
4761 def remove(ui, repo, *pats, **opts):
4756 def remove(ui, repo, *pats, **opts):
4762 """remove the specified files on the next commit
4757 """remove the specified files on the next commit
4763
4758
4764 Schedule the indicated files for removal from the current branch.
4759 Schedule the indicated files for removal from the current branch.
4765
4760
4766 This command schedules the files to be removed at the next commit.
4761 This command schedules the files to be removed at the next commit.
4767 To undo a remove before that, see :hg:`revert`. To undo added
4762 To undo a remove before that, see :hg:`revert`. To undo added
4768 files, see :hg:`forget`.
4763 files, see :hg:`forget`.
4769
4764
4770 .. container:: verbose
4765 .. container:: verbose
4771
4766
4772 -A/--after can be used to remove only files that have already
4767 -A/--after can be used to remove only files that have already
4773 been deleted, -f/--force can be used to force deletion, and -Af
4768 been deleted, -f/--force can be used to force deletion, and -Af
4774 can be used to remove files from the next revision without
4769 can be used to remove files from the next revision without
4775 deleting them from the working directory.
4770 deleting them from the working directory.
4776
4771
4777 The following table details the behavior of remove for different
4772 The following table details the behavior of remove for different
4778 file states (columns) and option combinations (rows). The file
4773 file states (columns) and option combinations (rows). The file
4779 states are Added [A], Clean [C], Modified [M] and Missing [!]
4774 states are Added [A], Clean [C], Modified [M] and Missing [!]
4780 (as reported by :hg:`status`). The actions are Warn, Remove
4775 (as reported by :hg:`status`). The actions are Warn, Remove
4781 (from branch) and Delete (from disk):
4776 (from branch) and Delete (from disk):
4782
4777
4783 ========= == == == ==
4778 ========= == == == ==
4784 opt/state A C M !
4779 opt/state A C M !
4785 ========= == == == ==
4780 ========= == == == ==
4786 none W RD W R
4781 none W RD W R
4787 -f R RD RD R
4782 -f R RD RD R
4788 -A W W W R
4783 -A W W W R
4789 -Af R R R R
4784 -Af R R R R
4790 ========= == == == ==
4785 ========= == == == ==
4791
4786
4792 Note that remove never deletes files in Added [A] state from the
4787 Note that remove never deletes files in Added [A] state from the
4793 working directory, not even if option --force is specified.
4788 working directory, not even if option --force is specified.
4794
4789
4795 Returns 0 on success, 1 if any warnings encountered.
4790 Returns 0 on success, 1 if any warnings encountered.
4796 """
4791 """
4797
4792
4798 ret = 0
4793 ret = 0
4799 after, force = opts.get('after'), opts.get('force')
4794 after, force = opts.get('after'), opts.get('force')
4800 if not pats and not after:
4795 if not pats and not after:
4801 raise util.Abort(_('no files specified'))
4796 raise util.Abort(_('no files specified'))
4802
4797
4803 m = scmutil.match(repo[None], pats, opts)
4798 m = scmutil.match(repo[None], pats, opts)
4804 s = repo.status(match=m, clean=True)
4799 s = repo.status(match=m, clean=True)
4805 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4800 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4806
4801
4807 # warn about failure to delete explicit files/dirs
4802 # warn about failure to delete explicit files/dirs
4808 wctx = repo[None]
4803 wctx = repo[None]
4809 for f in m.files():
4804 for f in m.files():
4810 if f in repo.dirstate or f in wctx.dirs():
4805 if f in repo.dirstate or f in wctx.dirs():
4811 continue
4806 continue
4812 if os.path.exists(m.rel(f)):
4807 if os.path.exists(m.rel(f)):
4813 if os.path.isdir(m.rel(f)):
4808 if os.path.isdir(m.rel(f)):
4814 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4809 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4815 else:
4810 else:
4816 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4811 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4817 # missing files will generate a warning elsewhere
4812 # missing files will generate a warning elsewhere
4818 ret = 1
4813 ret = 1
4819
4814
4820 if force:
4815 if force:
4821 list = modified + deleted + clean + added
4816 list = modified + deleted + clean + added
4822 elif after:
4817 elif after:
4823 list = deleted
4818 list = deleted
4824 for f in modified + added + clean:
4819 for f in modified + added + clean:
4825 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4820 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4826 ret = 1
4821 ret = 1
4827 else:
4822 else:
4828 list = deleted + clean
4823 list = deleted + clean
4829 for f in modified:
4824 for f in modified:
4830 ui.warn(_('not removing %s: file is modified (use -f'
4825 ui.warn(_('not removing %s: file is modified (use -f'
4831 ' to force removal)\n') % m.rel(f))
4826 ' to force removal)\n') % m.rel(f))
4832 ret = 1
4827 ret = 1
4833 for f in added:
4828 for f in added:
4834 ui.warn(_('not removing %s: file has been marked for add'
4829 ui.warn(_('not removing %s: file has been marked for add'
4835 ' (use forget to undo)\n') % m.rel(f))
4830 ' (use forget to undo)\n') % m.rel(f))
4836 ret = 1
4831 ret = 1
4837
4832
4838 for f in sorted(list):
4833 for f in sorted(list):
4839 if ui.verbose or not m.exact(f):
4834 if ui.verbose or not m.exact(f):
4840 ui.status(_('removing %s\n') % m.rel(f))
4835 ui.status(_('removing %s\n') % m.rel(f))
4841
4836
4842 wlock = repo.wlock()
4837 wlock = repo.wlock()
4843 try:
4838 try:
4844 if not after:
4839 if not after:
4845 for f in list:
4840 for f in list:
4846 if f in added:
4841 if f in added:
4847 continue # we never unlink added files on remove
4842 continue # we never unlink added files on remove
4848 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4843 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4849 repo[None].forget(list)
4844 repo[None].forget(list)
4850 finally:
4845 finally:
4851 wlock.release()
4846 wlock.release()
4852
4847
4853 return ret
4848 return ret
4854
4849
4855 @command('rename|move|mv',
4850 @command('rename|move|mv',
4856 [('A', 'after', None, _('record a rename that has already occurred')),
4851 [('A', 'after', None, _('record a rename that has already occurred')),
4857 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4852 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4858 ] + walkopts + dryrunopts,
4853 ] + walkopts + dryrunopts,
4859 _('[OPTION]... SOURCE... DEST'))
4854 _('[OPTION]... SOURCE... DEST'))
4860 def rename(ui, repo, *pats, **opts):
4855 def rename(ui, repo, *pats, **opts):
4861 """rename files; equivalent of copy + remove
4856 """rename files; equivalent of copy + remove
4862
4857
4863 Mark dest as copies of sources; mark sources for deletion. If dest
4858 Mark dest as copies of sources; mark sources for deletion. If dest
4864 is a directory, copies are put in that directory. If dest is a
4859 is a directory, copies are put in that directory. If dest is a
4865 file, there can only be one source.
4860 file, there can only be one source.
4866
4861
4867 By default, this command copies the contents of files as they
4862 By default, this command copies the contents of files as they
4868 exist in the working directory. If invoked with -A/--after, the
4863 exist in the working directory. If invoked with -A/--after, the
4869 operation is recorded, but no copying is performed.
4864 operation is recorded, but no copying is performed.
4870
4865
4871 This command takes effect at the next commit. To undo a rename
4866 This command takes effect at the next commit. To undo a rename
4872 before that, see :hg:`revert`.
4867 before that, see :hg:`revert`.
4873
4868
4874 Returns 0 on success, 1 if errors are encountered.
4869 Returns 0 on success, 1 if errors are encountered.
4875 """
4870 """
4876 wlock = repo.wlock(False)
4871 wlock = repo.wlock(False)
4877 try:
4872 try:
4878 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4873 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4879 finally:
4874 finally:
4880 wlock.release()
4875 wlock.release()
4881
4876
4882 @command('resolve',
4877 @command('resolve',
4883 [('a', 'all', None, _('select all unresolved files')),
4878 [('a', 'all', None, _('select all unresolved files')),
4884 ('l', 'list', None, _('list state of files needing merge')),
4879 ('l', 'list', None, _('list state of files needing merge')),
4885 ('m', 'mark', None, _('mark files as resolved')),
4880 ('m', 'mark', None, _('mark files as resolved')),
4886 ('u', 'unmark', None, _('mark files as unresolved')),
4881 ('u', 'unmark', None, _('mark files as unresolved')),
4887 ('n', 'no-status', None, _('hide status prefix'))]
4882 ('n', 'no-status', None, _('hide status prefix'))]
4888 + mergetoolopts + walkopts,
4883 + mergetoolopts + walkopts,
4889 _('[OPTION]... [FILE]...'))
4884 _('[OPTION]... [FILE]...'))
4890 def resolve(ui, repo, *pats, **opts):
4885 def resolve(ui, repo, *pats, **opts):
4891 """redo merges or set/view the merge status of files
4886 """redo merges or set/view the merge status of files
4892
4887
4893 Merges with unresolved conflicts are often the result of
4888 Merges with unresolved conflicts are often the result of
4894 non-interactive merging using the ``internal:merge`` configuration
4889 non-interactive merging using the ``internal:merge`` configuration
4895 setting, or a command-line merge tool like ``diff3``. The resolve
4890 setting, or a command-line merge tool like ``diff3``. The resolve
4896 command is used to manage the files involved in a merge, after
4891 command is used to manage the files involved in a merge, after
4897 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4892 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4898 working directory must have two parents). See :hg:`help
4893 working directory must have two parents). See :hg:`help
4899 merge-tools` for information on configuring merge tools.
4894 merge-tools` for information on configuring merge tools.
4900
4895
4901 The resolve command can be used in the following ways:
4896 The resolve command can be used in the following ways:
4902
4897
4903 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4898 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4904 files, discarding any previous merge attempts. Re-merging is not
4899 files, discarding any previous merge attempts. Re-merging is not
4905 performed for files already marked as resolved. Use ``--all/-a``
4900 performed for files already marked as resolved. Use ``--all/-a``
4906 to select all unresolved files. ``--tool`` can be used to specify
4901 to select all unresolved files. ``--tool`` can be used to specify
4907 the merge tool used for the given files. It overrides the HGMERGE
4902 the merge tool used for the given files. It overrides the HGMERGE
4908 environment variable and your configuration files. Previous file
4903 environment variable and your configuration files. Previous file
4909 contents are saved with a ``.orig`` suffix.
4904 contents are saved with a ``.orig`` suffix.
4910
4905
4911 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4906 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4912 (e.g. after having manually fixed-up the files). The default is
4907 (e.g. after having manually fixed-up the files). The default is
4913 to mark all unresolved files.
4908 to mark all unresolved files.
4914
4909
4915 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4910 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4916 default is to mark all resolved files.
4911 default is to mark all resolved files.
4917
4912
4918 - :hg:`resolve -l`: list files which had or still have conflicts.
4913 - :hg:`resolve -l`: list files which had or still have conflicts.
4919 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4914 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4920
4915
4921 Note that Mercurial will not let you commit files with unresolved
4916 Note that Mercurial will not let you commit files with unresolved
4922 merge conflicts. You must use :hg:`resolve -m ...` before you can
4917 merge conflicts. You must use :hg:`resolve -m ...` before you can
4923 commit after a conflicting merge.
4918 commit after a conflicting merge.
4924
4919
4925 Returns 0 on success, 1 if any files fail a resolve attempt.
4920 Returns 0 on success, 1 if any files fail a resolve attempt.
4926 """
4921 """
4927
4922
4928 all, mark, unmark, show, nostatus = \
4923 all, mark, unmark, show, nostatus = \
4929 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4924 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4930
4925
4931 if (show and (mark or unmark)) or (mark and unmark):
4926 if (show and (mark or unmark)) or (mark and unmark):
4932 raise util.Abort(_("too many options specified"))
4927 raise util.Abort(_("too many options specified"))
4933 if pats and all:
4928 if pats and all:
4934 raise util.Abort(_("can't specify --all and patterns"))
4929 raise util.Abort(_("can't specify --all and patterns"))
4935 if not (all or pats or show or mark or unmark):
4930 if not (all or pats or show or mark or unmark):
4936 raise util.Abort(_('no files or directories specified; '
4931 raise util.Abort(_('no files or directories specified; '
4937 'use --all to remerge all files'))
4932 'use --all to remerge all files'))
4938
4933
4939 ms = mergemod.mergestate(repo)
4934 ms = mergemod.mergestate(repo)
4940 m = scmutil.match(repo[None], pats, opts)
4935 m = scmutil.match(repo[None], pats, opts)
4941 ret = 0
4936 ret = 0
4942
4937
4943 for f in ms:
4938 for f in ms:
4944 if m(f):
4939 if m(f):
4945 if show:
4940 if show:
4946 if nostatus:
4941 if nostatus:
4947 ui.write("%s\n" % f)
4942 ui.write("%s\n" % f)
4948 else:
4943 else:
4949 ui.write("%s %s\n" % (ms[f].upper(), f),
4944 ui.write("%s %s\n" % (ms[f].upper(), f),
4950 label='resolve.' +
4945 label='resolve.' +
4951 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4946 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4952 elif mark:
4947 elif mark:
4953 ms.mark(f, "r")
4948 ms.mark(f, "r")
4954 elif unmark:
4949 elif unmark:
4955 ms.mark(f, "u")
4950 ms.mark(f, "u")
4956 else:
4951 else:
4957 wctx = repo[None]
4952 wctx = repo[None]
4958
4953
4959 # backup pre-resolve (merge uses .orig for its own purposes)
4954 # backup pre-resolve (merge uses .orig for its own purposes)
4960 a = repo.wjoin(f)
4955 a = repo.wjoin(f)
4961 util.copyfile(a, a + ".resolve")
4956 util.copyfile(a, a + ".resolve")
4962
4957
4963 try:
4958 try:
4964 # resolve file
4959 # resolve file
4965 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4960 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4966 if ms.resolve(f, wctx):
4961 if ms.resolve(f, wctx):
4967 ret = 1
4962 ret = 1
4968 finally:
4963 finally:
4969 ui.setconfig('ui', 'forcemerge', '')
4964 ui.setconfig('ui', 'forcemerge', '')
4970 ms.commit()
4965 ms.commit()
4971
4966
4972 # replace filemerge's .orig file with our resolve file
4967 # replace filemerge's .orig file with our resolve file
4973 util.rename(a + ".resolve", a + ".orig")
4968 util.rename(a + ".resolve", a + ".orig")
4974
4969
4975 ms.commit()
4970 ms.commit()
4976 return ret
4971 return ret
4977
4972
4978 @command('revert',
4973 @command('revert',
4979 [('a', 'all', None, _('revert all changes when no arguments given')),
4974 [('a', 'all', None, _('revert all changes when no arguments given')),
4980 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4975 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4981 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4976 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4982 ('C', 'no-backup', None, _('do not save backup copies of files')),
4977 ('C', 'no-backup', None, _('do not save backup copies of files')),
4983 ] + walkopts + dryrunopts,
4978 ] + walkopts + dryrunopts,
4984 _('[OPTION]... [-r REV] [NAME]...'))
4979 _('[OPTION]... [-r REV] [NAME]...'))
4985 def revert(ui, repo, *pats, **opts):
4980 def revert(ui, repo, *pats, **opts):
4986 """restore files to their checkout state
4981 """restore files to their checkout state
4987
4982
4988 .. note::
4983 .. note::
4989
4984
4990 To check out earlier revisions, you should use :hg:`update REV`.
4985 To check out earlier revisions, you should use :hg:`update REV`.
4991 To cancel an uncommitted merge (and lose your changes),
4986 To cancel an uncommitted merge (and lose your changes),
4992 use :hg:`update --clean .`.
4987 use :hg:`update --clean .`.
4993
4988
4994 With no revision specified, revert the specified files or directories
4989 With no revision specified, revert the specified files or directories
4995 to the contents they had in the parent of the working directory.
4990 to the contents they had in the parent of the working directory.
4996 This restores the contents of files to an unmodified
4991 This restores the contents of files to an unmodified
4997 state and unschedules adds, removes, copies, and renames. If the
4992 state and unschedules adds, removes, copies, and renames. If the
4998 working directory has two parents, you must explicitly specify a
4993 working directory has two parents, you must explicitly specify a
4999 revision.
4994 revision.
5000
4995
5001 Using the -r/--rev or -d/--date options, revert the given files or
4996 Using the -r/--rev or -d/--date options, revert the given files or
5002 directories to their states as of a specific revision. Because
4997 directories to their states as of a specific revision. Because
5003 revert does not change the working directory parents, this will
4998 revert does not change the working directory parents, this will
5004 cause these files to appear modified. This can be helpful to "back
4999 cause these files to appear modified. This can be helpful to "back
5005 out" some or all of an earlier change. See :hg:`backout` for a
5000 out" some or all of an earlier change. See :hg:`backout` for a
5006 related method.
5001 related method.
5007
5002
5008 Modified files are saved with a .orig suffix before reverting.
5003 Modified files are saved with a .orig suffix before reverting.
5009 To disable these backups, use --no-backup.
5004 To disable these backups, use --no-backup.
5010
5005
5011 See :hg:`help dates` for a list of formats valid for -d/--date.
5006 See :hg:`help dates` for a list of formats valid for -d/--date.
5012
5007
5013 Returns 0 on success.
5008 Returns 0 on success.
5014 """
5009 """
5015
5010
5016 if opts.get("date"):
5011 if opts.get("date"):
5017 if opts.get("rev"):
5012 if opts.get("rev"):
5018 raise util.Abort(_("you can't specify a revision and a date"))
5013 raise util.Abort(_("you can't specify a revision and a date"))
5019 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5014 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5020
5015
5021 parent, p2 = repo.dirstate.parents()
5016 parent, p2 = repo.dirstate.parents()
5022 if not opts.get('rev') and p2 != nullid:
5017 if not opts.get('rev') and p2 != nullid:
5023 # revert after merge is a trap for new users (issue2915)
5018 # revert after merge is a trap for new users (issue2915)
5024 raise util.Abort(_('uncommitted merge with no revision specified'),
5019 raise util.Abort(_('uncommitted merge with no revision specified'),
5025 hint=_('use "hg update" or see "hg help revert"'))
5020 hint=_('use "hg update" or see "hg help revert"'))
5026
5021
5027 ctx = scmutil.revsingle(repo, opts.get('rev'))
5022 ctx = scmutil.revsingle(repo, opts.get('rev'))
5028
5023
5029 if not pats and not opts.get('all'):
5024 if not pats and not opts.get('all'):
5030 msg = _("no files or directories specified")
5025 msg = _("no files or directories specified")
5031 if p2 != nullid:
5026 if p2 != nullid:
5032 hint = _("uncommitted merge, use --all to discard all changes,"
5027 hint = _("uncommitted merge, use --all to discard all changes,"
5033 " or 'hg update -C .' to abort the merge")
5028 " or 'hg update -C .' to abort the merge")
5034 raise util.Abort(msg, hint=hint)
5029 raise util.Abort(msg, hint=hint)
5035 dirty = util.any(repo.status())
5030 dirty = util.any(repo.status())
5036 node = ctx.node()
5031 node = ctx.node()
5037 if node != parent:
5032 if node != parent:
5038 if dirty:
5033 if dirty:
5039 hint = _("uncommitted changes, use --all to discard all"
5034 hint = _("uncommitted changes, use --all to discard all"
5040 " changes, or 'hg update %s' to update") % ctx.rev()
5035 " changes, or 'hg update %s' to update") % ctx.rev()
5041 else:
5036 else:
5042 hint = _("use --all to revert all files,"
5037 hint = _("use --all to revert all files,"
5043 " or 'hg update %s' to update") % ctx.rev()
5038 " or 'hg update %s' to update") % ctx.rev()
5044 elif dirty:
5039 elif dirty:
5045 hint = _("uncommitted changes, use --all to discard all changes")
5040 hint = _("uncommitted changes, use --all to discard all changes")
5046 else:
5041 else:
5047 hint = _("use --all to revert all files")
5042 hint = _("use --all to revert all files")
5048 raise util.Abort(msg, hint=hint)
5043 raise util.Abort(msg, hint=hint)
5049
5044
5050 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5045 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5051
5046
5052 @command('rollback', dryrunopts +
5047 @command('rollback', dryrunopts +
5053 [('f', 'force', False, _('ignore safety measures'))])
5048 [('f', 'force', False, _('ignore safety measures'))])
5054 def rollback(ui, repo, **opts):
5049 def rollback(ui, repo, **opts):
5055 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5050 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5056
5051
5057 Please use :hg:`commit --amend` instead of rollback to correct
5052 Please use :hg:`commit --amend` instead of rollback to correct
5058 mistakes in the last commit.
5053 mistakes in the last commit.
5059
5054
5060 This command should be used with care. There is only one level of
5055 This command should be used with care. There is only one level of
5061 rollback, and there is no way to undo a rollback. It will also
5056 rollback, and there is no way to undo a rollback. It will also
5062 restore the dirstate at the time of the last transaction, losing
5057 restore the dirstate at the time of the last transaction, losing
5063 any dirstate changes since that time. This command does not alter
5058 any dirstate changes since that time. This command does not alter
5064 the working directory.
5059 the working directory.
5065
5060
5066 Transactions are used to encapsulate the effects of all commands
5061 Transactions are used to encapsulate the effects of all commands
5067 that create new changesets or propagate existing changesets into a
5062 that create new changesets or propagate existing changesets into a
5068 repository.
5063 repository.
5069
5064
5070 .. container:: verbose
5065 .. container:: verbose
5071
5066
5072 For example, the following commands are transactional, and their
5067 For example, the following commands are transactional, and their
5073 effects can be rolled back:
5068 effects can be rolled back:
5074
5069
5075 - commit
5070 - commit
5076 - import
5071 - import
5077 - pull
5072 - pull
5078 - push (with this repository as the destination)
5073 - push (with this repository as the destination)
5079 - unbundle
5074 - unbundle
5080
5075
5081 To avoid permanent data loss, rollback will refuse to rollback a
5076 To avoid permanent data loss, rollback will refuse to rollback a
5082 commit transaction if it isn't checked out. Use --force to
5077 commit transaction if it isn't checked out. Use --force to
5083 override this protection.
5078 override this protection.
5084
5079
5085 This command is not intended for use on public repositories. Once
5080 This command is not intended for use on public repositories. Once
5086 changes are visible for pull by other users, rolling a transaction
5081 changes are visible for pull by other users, rolling a transaction
5087 back locally is ineffective (someone else may already have pulled
5082 back locally is ineffective (someone else may already have pulled
5088 the changes). Furthermore, a race is possible with readers of the
5083 the changes). Furthermore, a race is possible with readers of the
5089 repository; for example an in-progress pull from the repository
5084 repository; for example an in-progress pull from the repository
5090 may fail if a rollback is performed.
5085 may fail if a rollback is performed.
5091
5086
5092 Returns 0 on success, 1 if no rollback data is available.
5087 Returns 0 on success, 1 if no rollback data is available.
5093 """
5088 """
5094 return repo.rollback(dryrun=opts.get('dry_run'),
5089 return repo.rollback(dryrun=opts.get('dry_run'),
5095 force=opts.get('force'))
5090 force=opts.get('force'))
5096
5091
5097 @command('root', [])
5092 @command('root', [])
5098 def root(ui, repo):
5093 def root(ui, repo):
5099 """print the root (top) of the current working directory
5094 """print the root (top) of the current working directory
5100
5095
5101 Print the root directory of the current repository.
5096 Print the root directory of the current repository.
5102
5097
5103 Returns 0 on success.
5098 Returns 0 on success.
5104 """
5099 """
5105 ui.write(repo.root + "\n")
5100 ui.write(repo.root + "\n")
5106
5101
5107 @command('^serve',
5102 @command('^serve',
5108 [('A', 'accesslog', '', _('name of access log file to write to'),
5103 [('A', 'accesslog', '', _('name of access log file to write to'),
5109 _('FILE')),
5104 _('FILE')),
5110 ('d', 'daemon', None, _('run server in background')),
5105 ('d', 'daemon', None, _('run server in background')),
5111 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5106 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5112 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5107 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5113 # use string type, then we can check if something was passed
5108 # use string type, then we can check if something was passed
5114 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5109 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5115 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5110 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5116 _('ADDR')),
5111 _('ADDR')),
5117 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5112 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5118 _('PREFIX')),
5113 _('PREFIX')),
5119 ('n', 'name', '',
5114 ('n', 'name', '',
5120 _('name to show in web pages (default: working directory)'), _('NAME')),
5115 _('name to show in web pages (default: working directory)'), _('NAME')),
5121 ('', 'web-conf', '',
5116 ('', 'web-conf', '',
5122 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5117 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5123 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5118 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5124 _('FILE')),
5119 _('FILE')),
5125 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5120 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5126 ('', 'stdio', None, _('for remote clients')),
5121 ('', 'stdio', None, _('for remote clients')),
5127 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5122 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5128 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5123 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5129 ('', 'style', '', _('template style to use'), _('STYLE')),
5124 ('', 'style', '', _('template style to use'), _('STYLE')),
5130 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5125 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5131 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5126 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5132 _('[OPTION]...'))
5127 _('[OPTION]...'))
5133 def serve(ui, repo, **opts):
5128 def serve(ui, repo, **opts):
5134 """start stand-alone webserver
5129 """start stand-alone webserver
5135
5130
5136 Start a local HTTP repository browser and pull server. You can use
5131 Start a local HTTP repository browser and pull server. You can use
5137 this for ad-hoc sharing and browsing of repositories. It is
5132 this for ad-hoc sharing and browsing of repositories. It is
5138 recommended to use a real web server to serve a repository for
5133 recommended to use a real web server to serve a repository for
5139 longer periods of time.
5134 longer periods of time.
5140
5135
5141 Please note that the server does not implement access control.
5136 Please note that the server does not implement access control.
5142 This means that, by default, anybody can read from the server and
5137 This means that, by default, anybody can read from the server and
5143 nobody can write to it by default. Set the ``web.allow_push``
5138 nobody can write to it by default. Set the ``web.allow_push``
5144 option to ``*`` to allow everybody to push to the server. You
5139 option to ``*`` to allow everybody to push to the server. You
5145 should use a real web server if you need to authenticate users.
5140 should use a real web server if you need to authenticate users.
5146
5141
5147 By default, the server logs accesses to stdout and errors to
5142 By default, the server logs accesses to stdout and errors to
5148 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5143 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5149 files.
5144 files.
5150
5145
5151 To have the server choose a free port number to listen on, specify
5146 To have the server choose a free port number to listen on, specify
5152 a port number of 0; in this case, the server will print the port
5147 a port number of 0; in this case, the server will print the port
5153 number it uses.
5148 number it uses.
5154
5149
5155 Returns 0 on success.
5150 Returns 0 on success.
5156 """
5151 """
5157
5152
5158 if opts["stdio"] and opts["cmdserver"]:
5153 if opts["stdio"] and opts["cmdserver"]:
5159 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5154 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5160
5155
5161 def checkrepo():
5156 def checkrepo():
5162 if repo is None:
5157 if repo is None:
5163 raise error.RepoError(_("there is no Mercurial repository here"
5158 raise error.RepoError(_("there is no Mercurial repository here"
5164 " (.hg not found)"))
5159 " (.hg not found)"))
5165
5160
5166 if opts["stdio"]:
5161 if opts["stdio"]:
5167 checkrepo()
5162 checkrepo()
5168 s = sshserver.sshserver(ui, repo)
5163 s = sshserver.sshserver(ui, repo)
5169 s.serve_forever()
5164 s.serve_forever()
5170
5165
5171 if opts["cmdserver"]:
5166 if opts["cmdserver"]:
5172 s = commandserver.server(ui, repo, opts["cmdserver"])
5167 s = commandserver.server(ui, repo, opts["cmdserver"])
5173 return s.serve()
5168 return s.serve()
5174
5169
5175 # this way we can check if something was given in the command-line
5170 # this way we can check if something was given in the command-line
5176 if opts.get('port'):
5171 if opts.get('port'):
5177 opts['port'] = util.getport(opts.get('port'))
5172 opts['port'] = util.getport(opts.get('port'))
5178
5173
5179 baseui = repo and repo.baseui or ui
5174 baseui = repo and repo.baseui or ui
5180 optlist = ("name templates style address port prefix ipv6"
5175 optlist = ("name templates style address port prefix ipv6"
5181 " accesslog errorlog certificate encoding")
5176 " accesslog errorlog certificate encoding")
5182 for o in optlist.split():
5177 for o in optlist.split():
5183 val = opts.get(o, '')
5178 val = opts.get(o, '')
5184 if val in (None, ''): # should check against default options instead
5179 if val in (None, ''): # should check against default options instead
5185 continue
5180 continue
5186 baseui.setconfig("web", o, val)
5181 baseui.setconfig("web", o, val)
5187 if repo and repo.ui != baseui:
5182 if repo and repo.ui != baseui:
5188 repo.ui.setconfig("web", o, val)
5183 repo.ui.setconfig("web", o, val)
5189
5184
5190 o = opts.get('web_conf') or opts.get('webdir_conf')
5185 o = opts.get('web_conf') or opts.get('webdir_conf')
5191 if not o:
5186 if not o:
5192 if not repo:
5187 if not repo:
5193 raise error.RepoError(_("there is no Mercurial repository"
5188 raise error.RepoError(_("there is no Mercurial repository"
5194 " here (.hg not found)"))
5189 " here (.hg not found)"))
5195 o = repo
5190 o = repo
5196
5191
5197 app = hgweb.hgweb(o, baseui=baseui)
5192 app = hgweb.hgweb(o, baseui=baseui)
5198 service = httpservice(ui, app, opts)
5193 service = httpservice(ui, app, opts)
5199 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5194 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5200
5195
5201 class httpservice(object):
5196 class httpservice(object):
5202 def __init__(self, ui, app, opts):
5197 def __init__(self, ui, app, opts):
5203 self.ui = ui
5198 self.ui = ui
5204 self.app = app
5199 self.app = app
5205 self.opts = opts
5200 self.opts = opts
5206
5201
5207 def init(self):
5202 def init(self):
5208 util.setsignalhandler()
5203 util.setsignalhandler()
5209 self.httpd = hgweb_server.create_server(self.ui, self.app)
5204 self.httpd = hgweb_server.create_server(self.ui, self.app)
5210
5205
5211 if self.opts['port'] and not self.ui.verbose:
5206 if self.opts['port'] and not self.ui.verbose:
5212 return
5207 return
5213
5208
5214 if self.httpd.prefix:
5209 if self.httpd.prefix:
5215 prefix = self.httpd.prefix.strip('/') + '/'
5210 prefix = self.httpd.prefix.strip('/') + '/'
5216 else:
5211 else:
5217 prefix = ''
5212 prefix = ''
5218
5213
5219 port = ':%d' % self.httpd.port
5214 port = ':%d' % self.httpd.port
5220 if port == ':80':
5215 if port == ':80':
5221 port = ''
5216 port = ''
5222
5217
5223 bindaddr = self.httpd.addr
5218 bindaddr = self.httpd.addr
5224 if bindaddr == '0.0.0.0':
5219 if bindaddr == '0.0.0.0':
5225 bindaddr = '*'
5220 bindaddr = '*'
5226 elif ':' in bindaddr: # IPv6
5221 elif ':' in bindaddr: # IPv6
5227 bindaddr = '[%s]' % bindaddr
5222 bindaddr = '[%s]' % bindaddr
5228
5223
5229 fqaddr = self.httpd.fqaddr
5224 fqaddr = self.httpd.fqaddr
5230 if ':' in fqaddr:
5225 if ':' in fqaddr:
5231 fqaddr = '[%s]' % fqaddr
5226 fqaddr = '[%s]' % fqaddr
5232 if self.opts['port']:
5227 if self.opts['port']:
5233 write = self.ui.status
5228 write = self.ui.status
5234 else:
5229 else:
5235 write = self.ui.write
5230 write = self.ui.write
5236 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5231 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5237 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5232 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5238
5233
5239 def run(self):
5234 def run(self):
5240 self.httpd.serve_forever()
5235 self.httpd.serve_forever()
5241
5236
5242
5237
5243 @command('^status|st',
5238 @command('^status|st',
5244 [('A', 'all', None, _('show status of all files')),
5239 [('A', 'all', None, _('show status of all files')),
5245 ('m', 'modified', None, _('show only modified files')),
5240 ('m', 'modified', None, _('show only modified files')),
5246 ('a', 'added', None, _('show only added files')),
5241 ('a', 'added', None, _('show only added files')),
5247 ('r', 'removed', None, _('show only removed files')),
5242 ('r', 'removed', None, _('show only removed files')),
5248 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5243 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5249 ('c', 'clean', None, _('show only files without changes')),
5244 ('c', 'clean', None, _('show only files without changes')),
5250 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5245 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5251 ('i', 'ignored', None, _('show only ignored files')),
5246 ('i', 'ignored', None, _('show only ignored files')),
5252 ('n', 'no-status', None, _('hide status prefix')),
5247 ('n', 'no-status', None, _('hide status prefix')),
5253 ('C', 'copies', None, _('show source of copied files')),
5248 ('C', 'copies', None, _('show source of copied files')),
5254 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5249 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5255 ('', 'rev', [], _('show difference from revision'), _('REV')),
5250 ('', 'rev', [], _('show difference from revision'), _('REV')),
5256 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5251 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5257 ] + walkopts + subrepoopts,
5252 ] + walkopts + subrepoopts,
5258 _('[OPTION]... [FILE]...'))
5253 _('[OPTION]... [FILE]...'))
5259 def status(ui, repo, *pats, **opts):
5254 def status(ui, repo, *pats, **opts):
5260 """show changed files in the working directory
5255 """show changed files in the working directory
5261
5256
5262 Show status of files in the repository. If names are given, only
5257 Show status of files in the repository. If names are given, only
5263 files that match are shown. Files that are clean or ignored or
5258 files that match are shown. Files that are clean or ignored or
5264 the source of a copy/move operation, are not listed unless
5259 the source of a copy/move operation, are not listed unless
5265 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5260 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5266 Unless options described with "show only ..." are given, the
5261 Unless options described with "show only ..." are given, the
5267 options -mardu are used.
5262 options -mardu are used.
5268
5263
5269 Option -q/--quiet hides untracked (unknown and ignored) files
5264 Option -q/--quiet hides untracked (unknown and ignored) files
5270 unless explicitly requested with -u/--unknown or -i/--ignored.
5265 unless explicitly requested with -u/--unknown or -i/--ignored.
5271
5266
5272 .. note::
5267 .. note::
5273
5268
5274 status may appear to disagree with diff if permissions have
5269 status may appear to disagree with diff if permissions have
5275 changed or a merge has occurred. The standard diff format does
5270 changed or a merge has occurred. The standard diff format does
5276 not report permission changes and diff only reports changes
5271 not report permission changes and diff only reports changes
5277 relative to one merge parent.
5272 relative to one merge parent.
5278
5273
5279 If one revision is given, it is used as the base revision.
5274 If one revision is given, it is used as the base revision.
5280 If two revisions are given, the differences between them are
5275 If two revisions are given, the differences between them are
5281 shown. The --change option can also be used as a shortcut to list
5276 shown. The --change option can also be used as a shortcut to list
5282 the changed files of a revision from its first parent.
5277 the changed files of a revision from its first parent.
5283
5278
5284 The codes used to show the status of files are::
5279 The codes used to show the status of files are::
5285
5280
5286 M = modified
5281 M = modified
5287 A = added
5282 A = added
5288 R = removed
5283 R = removed
5289 C = clean
5284 C = clean
5290 ! = missing (deleted by non-hg command, but still tracked)
5285 ! = missing (deleted by non-hg command, but still tracked)
5291 ? = not tracked
5286 ? = not tracked
5292 I = ignored
5287 I = ignored
5293 = origin of the previous file (with --copies)
5288 = origin of the previous file (with --copies)
5294
5289
5295 .. container:: verbose
5290 .. container:: verbose
5296
5291
5297 Examples:
5292 Examples:
5298
5293
5299 - show changes in the working directory relative to a
5294 - show changes in the working directory relative to a
5300 changeset::
5295 changeset::
5301
5296
5302 hg status --rev 9353
5297 hg status --rev 9353
5303
5298
5304 - show all changes including copies in an existing changeset::
5299 - show all changes including copies in an existing changeset::
5305
5300
5306 hg status --copies --change 9353
5301 hg status --copies --change 9353
5307
5302
5308 - get a NUL separated list of added files, suitable for xargs::
5303 - get a NUL separated list of added files, suitable for xargs::
5309
5304
5310 hg status -an0
5305 hg status -an0
5311
5306
5312 Returns 0 on success.
5307 Returns 0 on success.
5313 """
5308 """
5314
5309
5315 revs = opts.get('rev')
5310 revs = opts.get('rev')
5316 change = opts.get('change')
5311 change = opts.get('change')
5317
5312
5318 if revs and change:
5313 if revs and change:
5319 msg = _('cannot specify --rev and --change at the same time')
5314 msg = _('cannot specify --rev and --change at the same time')
5320 raise util.Abort(msg)
5315 raise util.Abort(msg)
5321 elif change:
5316 elif change:
5322 node2 = scmutil.revsingle(repo, change, None).node()
5317 node2 = scmutil.revsingle(repo, change, None).node()
5323 node1 = repo[node2].p1().node()
5318 node1 = repo[node2].p1().node()
5324 else:
5319 else:
5325 node1, node2 = scmutil.revpair(repo, revs)
5320 node1, node2 = scmutil.revpair(repo, revs)
5326
5321
5327 cwd = (pats and repo.getcwd()) or ''
5322 cwd = (pats and repo.getcwd()) or ''
5328 end = opts.get('print0') and '\0' or '\n'
5323 end = opts.get('print0') and '\0' or '\n'
5329 copy = {}
5324 copy = {}
5330 states = 'modified added removed deleted unknown ignored clean'.split()
5325 states = 'modified added removed deleted unknown ignored clean'.split()
5331 show = [k for k in states if opts.get(k)]
5326 show = [k for k in states if opts.get(k)]
5332 if opts.get('all'):
5327 if opts.get('all'):
5333 show += ui.quiet and (states[:4] + ['clean']) or states
5328 show += ui.quiet and (states[:4] + ['clean']) or states
5334 if not show:
5329 if not show:
5335 show = ui.quiet and states[:4] or states[:5]
5330 show = ui.quiet and states[:4] or states[:5]
5336
5331
5337 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5332 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5338 'ignored' in show, 'clean' in show, 'unknown' in show,
5333 'ignored' in show, 'clean' in show, 'unknown' in show,
5339 opts.get('subrepos'))
5334 opts.get('subrepos'))
5340 changestates = zip(states, 'MAR!?IC', stat)
5335 changestates = zip(states, 'MAR!?IC', stat)
5341
5336
5342 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5337 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5343 copy = copies.pathcopies(repo[node1], repo[node2])
5338 copy = copies.pathcopies(repo[node1], repo[node2])
5344
5339
5345 fm = ui.formatter('status', opts)
5340 fm = ui.formatter('status', opts)
5346 fmt = '%s' + end
5341 fmt = '%s' + end
5347 showchar = not opts.get('no_status')
5342 showchar = not opts.get('no_status')
5348
5343
5349 for state, char, files in changestates:
5344 for state, char, files in changestates:
5350 if state in show:
5345 if state in show:
5351 label = 'status.' + state
5346 label = 'status.' + state
5352 for f in files:
5347 for f in files:
5353 fm.startitem()
5348 fm.startitem()
5354 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5349 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5355 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5350 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5356 if f in copy:
5351 if f in copy:
5357 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5352 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5358 label='status.copied')
5353 label='status.copied')
5359 fm.end()
5354 fm.end()
5360
5355
5361 @command('^summary|sum',
5356 @command('^summary|sum',
5362 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5357 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5363 def summary(ui, repo, **opts):
5358 def summary(ui, repo, **opts):
5364 """summarize working directory state
5359 """summarize working directory state
5365
5360
5366 This generates a brief summary of the working directory state,
5361 This generates a brief summary of the working directory state,
5367 including parents, branch, commit status, and available updates.
5362 including parents, branch, commit status, and available updates.
5368
5363
5369 With the --remote option, this will check the default paths for
5364 With the --remote option, this will check the default paths for
5370 incoming and outgoing changes. This can be time-consuming.
5365 incoming and outgoing changes. This can be time-consuming.
5371
5366
5372 Returns 0 on success.
5367 Returns 0 on success.
5373 """
5368 """
5374
5369
5375 ctx = repo[None]
5370 ctx = repo[None]
5376 parents = ctx.parents()
5371 parents = ctx.parents()
5377 pnode = parents[0].node()
5372 pnode = parents[0].node()
5378 marks = []
5373 marks = []
5379
5374
5380 for p in parents:
5375 for p in parents:
5381 # label with log.changeset (instead of log.parent) since this
5376 # label with log.changeset (instead of log.parent) since this
5382 # shows a working directory parent *changeset*:
5377 # shows a working directory parent *changeset*:
5383 # i18n: column positioning for "hg summary"
5378 # i18n: column positioning for "hg summary"
5384 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5379 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5385 label='log.changeset changeset.%s' % p.phasestr())
5380 label='log.changeset changeset.%s' % p.phasestr())
5386 ui.write(' '.join(p.tags()), label='log.tag')
5381 ui.write(' '.join(p.tags()), label='log.tag')
5387 if p.bookmarks():
5382 if p.bookmarks():
5388 marks.extend(p.bookmarks())
5383 marks.extend(p.bookmarks())
5389 if p.rev() == -1:
5384 if p.rev() == -1:
5390 if not len(repo):
5385 if not len(repo):
5391 ui.write(_(' (empty repository)'))
5386 ui.write(_(' (empty repository)'))
5392 else:
5387 else:
5393 ui.write(_(' (no revision checked out)'))
5388 ui.write(_(' (no revision checked out)'))
5394 ui.write('\n')
5389 ui.write('\n')
5395 if p.description():
5390 if p.description():
5396 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5391 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5397 label='log.summary')
5392 label='log.summary')
5398
5393
5399 branch = ctx.branch()
5394 branch = ctx.branch()
5400 bheads = repo.branchheads(branch)
5395 bheads = repo.branchheads(branch)
5401 # i18n: column positioning for "hg summary"
5396 # i18n: column positioning for "hg summary"
5402 m = _('branch: %s\n') % branch
5397 m = _('branch: %s\n') % branch
5403 if branch != 'default':
5398 if branch != 'default':
5404 ui.write(m, label='log.branch')
5399 ui.write(m, label='log.branch')
5405 else:
5400 else:
5406 ui.status(m, label='log.branch')
5401 ui.status(m, label='log.branch')
5407
5402
5408 if marks:
5403 if marks:
5409 current = repo._bookmarkcurrent
5404 current = repo._bookmarkcurrent
5410 # i18n: column positioning for "hg summary"
5405 # i18n: column positioning for "hg summary"
5411 ui.write(_('bookmarks:'), label='log.bookmark')
5406 ui.write(_('bookmarks:'), label='log.bookmark')
5412 if current is not None:
5407 if current is not None:
5413 if current in marks:
5408 if current in marks:
5414 ui.write(' *' + current, label='bookmarks.current')
5409 ui.write(' *' + current, label='bookmarks.current')
5415 marks.remove(current)
5410 marks.remove(current)
5416 else:
5411 else:
5417 ui.write(' [%s]' % current, label='bookmarks.current')
5412 ui.write(' [%s]' % current, label='bookmarks.current')
5418 for m in marks:
5413 for m in marks:
5419 ui.write(' ' + m, label='log.bookmark')
5414 ui.write(' ' + m, label='log.bookmark')
5420 ui.write('\n', label='log.bookmark')
5415 ui.write('\n', label='log.bookmark')
5421
5416
5422 st = list(repo.status(unknown=True))[:6]
5417 st = list(repo.status(unknown=True))[:6]
5423
5418
5424 c = repo.dirstate.copies()
5419 c = repo.dirstate.copies()
5425 copied, renamed = [], []
5420 copied, renamed = [], []
5426 for d, s in c.iteritems():
5421 for d, s in c.iteritems():
5427 if s in st[2]:
5422 if s in st[2]:
5428 st[2].remove(s)
5423 st[2].remove(s)
5429 renamed.append(d)
5424 renamed.append(d)
5430 else:
5425 else:
5431 copied.append(d)
5426 copied.append(d)
5432 if d in st[1]:
5427 if d in st[1]:
5433 st[1].remove(d)
5428 st[1].remove(d)
5434 st.insert(3, renamed)
5429 st.insert(3, renamed)
5435 st.insert(4, copied)
5430 st.insert(4, copied)
5436
5431
5437 ms = mergemod.mergestate(repo)
5432 ms = mergemod.mergestate(repo)
5438 st.append([f for f in ms if ms[f] == 'u'])
5433 st.append([f for f in ms if ms[f] == 'u'])
5439
5434
5440 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5435 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5441 st.append(subs)
5436 st.append(subs)
5442
5437
5443 labels = [ui.label(_('%d modified'), 'status.modified'),
5438 labels = [ui.label(_('%d modified'), 'status.modified'),
5444 ui.label(_('%d added'), 'status.added'),
5439 ui.label(_('%d added'), 'status.added'),
5445 ui.label(_('%d removed'), 'status.removed'),
5440 ui.label(_('%d removed'), 'status.removed'),
5446 ui.label(_('%d renamed'), 'status.copied'),
5441 ui.label(_('%d renamed'), 'status.copied'),
5447 ui.label(_('%d copied'), 'status.copied'),
5442 ui.label(_('%d copied'), 'status.copied'),
5448 ui.label(_('%d deleted'), 'status.deleted'),
5443 ui.label(_('%d deleted'), 'status.deleted'),
5449 ui.label(_('%d unknown'), 'status.unknown'),
5444 ui.label(_('%d unknown'), 'status.unknown'),
5450 ui.label(_('%d ignored'), 'status.ignored'),
5445 ui.label(_('%d ignored'), 'status.ignored'),
5451 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5446 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5452 ui.label(_('%d subrepos'), 'status.modified')]
5447 ui.label(_('%d subrepos'), 'status.modified')]
5453 t = []
5448 t = []
5454 for s, l in zip(st, labels):
5449 for s, l in zip(st, labels):
5455 if s:
5450 if s:
5456 t.append(l % len(s))
5451 t.append(l % len(s))
5457
5452
5458 t = ', '.join(t)
5453 t = ', '.join(t)
5459 cleanworkdir = False
5454 cleanworkdir = False
5460
5455
5461 if repo.vfs.exists('updatestate'):
5456 if repo.vfs.exists('updatestate'):
5462 t += _(' (interrupted update)')
5457 t += _(' (interrupted update)')
5463 elif len(parents) > 1:
5458 elif len(parents) > 1:
5464 t += _(' (merge)')
5459 t += _(' (merge)')
5465 elif branch != parents[0].branch():
5460 elif branch != parents[0].branch():
5466 t += _(' (new branch)')
5461 t += _(' (new branch)')
5467 elif (parents[0].closesbranch() and
5462 elif (parents[0].closesbranch() and
5468 pnode in repo.branchheads(branch, closed=True)):
5463 pnode in repo.branchheads(branch, closed=True)):
5469 t += _(' (head closed)')
5464 t += _(' (head closed)')
5470 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5465 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5471 t += _(' (clean)')
5466 t += _(' (clean)')
5472 cleanworkdir = True
5467 cleanworkdir = True
5473 elif pnode not in bheads:
5468 elif pnode not in bheads:
5474 t += _(' (new branch head)')
5469 t += _(' (new branch head)')
5475
5470
5476 if cleanworkdir:
5471 if cleanworkdir:
5477 # i18n: column positioning for "hg summary"
5472 # i18n: column positioning for "hg summary"
5478 ui.status(_('commit: %s\n') % t.strip())
5473 ui.status(_('commit: %s\n') % t.strip())
5479 else:
5474 else:
5480 # i18n: column positioning for "hg summary"
5475 # i18n: column positioning for "hg summary"
5481 ui.write(_('commit: %s\n') % t.strip())
5476 ui.write(_('commit: %s\n') % t.strip())
5482
5477
5483 # all ancestors of branch heads - all ancestors of parent = new csets
5478 # all ancestors of branch heads - all ancestors of parent = new csets
5484 new = len(repo.changelog.findmissing([ctx.node() for ctx in parents],
5479 new = len(repo.changelog.findmissing([ctx.node() for ctx in parents],
5485 bheads))
5480 bheads))
5486
5481
5487 if new == 0:
5482 if new == 0:
5488 # i18n: column positioning for "hg summary"
5483 # i18n: column positioning for "hg summary"
5489 ui.status(_('update: (current)\n'))
5484 ui.status(_('update: (current)\n'))
5490 elif pnode not in bheads:
5485 elif pnode not in bheads:
5491 # i18n: column positioning for "hg summary"
5486 # i18n: column positioning for "hg summary"
5492 ui.write(_('update: %d new changesets (update)\n') % new)
5487 ui.write(_('update: %d new changesets (update)\n') % new)
5493 else:
5488 else:
5494 # i18n: column positioning for "hg summary"
5489 # i18n: column positioning for "hg summary"
5495 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5490 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5496 (new, len(bheads)))
5491 (new, len(bheads)))
5497
5492
5498 cmdutil.summaryhooks(ui, repo)
5493 cmdutil.summaryhooks(ui, repo)
5499
5494
5500 if opts.get('remote'):
5495 if opts.get('remote'):
5501 t = []
5496 t = []
5502 source, branches = hg.parseurl(ui.expandpath('default'))
5497 source, branches = hg.parseurl(ui.expandpath('default'))
5503 sbranch = branches[0]
5498 sbranch = branches[0]
5504 other = hg.peer(repo, {}, source)
5499 other = hg.peer(repo, {}, source)
5505 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5500 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5506 if revs:
5501 if revs:
5507 revs = [other.lookup(rev) for rev in revs]
5502 revs = [other.lookup(rev) for rev in revs]
5508 ui.debug('comparing with %s\n' % util.hidepassword(source))
5503 ui.debug('comparing with %s\n' % util.hidepassword(source))
5509 repo.ui.pushbuffer()
5504 repo.ui.pushbuffer()
5510 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5505 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5511 _common, incoming, _rheads = commoninc
5506 _common, incoming, _rheads = commoninc
5512 repo.ui.popbuffer()
5507 repo.ui.popbuffer()
5513 if incoming:
5508 if incoming:
5514 t.append(_('1 or more incoming'))
5509 t.append(_('1 or more incoming'))
5515
5510
5516 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5511 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5517 dbranch = branches[0]
5512 dbranch = branches[0]
5518 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5513 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5519 if source != dest:
5514 if source != dest:
5520 other = hg.peer(repo, {}, dest)
5515 other = hg.peer(repo, {}, dest)
5521 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5516 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5522 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5517 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5523 commoninc = None
5518 commoninc = None
5524 if revs:
5519 if revs:
5525 revs = [repo.lookup(rev) for rev in revs]
5520 revs = [repo.lookup(rev) for rev in revs]
5526 repo.ui.pushbuffer()
5521 repo.ui.pushbuffer()
5527 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs,
5522 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs,
5528 commoninc=commoninc)
5523 commoninc=commoninc)
5529 repo.ui.popbuffer()
5524 repo.ui.popbuffer()
5530 o = outgoing.missing
5525 o = outgoing.missing
5531 if o:
5526 if o:
5532 t.append(_('%d outgoing') % len(o))
5527 t.append(_('%d outgoing') % len(o))
5533 if 'bookmarks' in other.listkeys('namespaces'):
5528 if 'bookmarks' in other.listkeys('namespaces'):
5534 lmarks = repo.listkeys('bookmarks')
5529 lmarks = repo.listkeys('bookmarks')
5535 rmarks = other.listkeys('bookmarks')
5530 rmarks = other.listkeys('bookmarks')
5536 diff = set(rmarks) - set(lmarks)
5531 diff = set(rmarks) - set(lmarks)
5537 if len(diff) > 0:
5532 if len(diff) > 0:
5538 t.append(_('%d incoming bookmarks') % len(diff))
5533 t.append(_('%d incoming bookmarks') % len(diff))
5539 diff = set(lmarks) - set(rmarks)
5534 diff = set(lmarks) - set(rmarks)
5540 if len(diff) > 0:
5535 if len(diff) > 0:
5541 t.append(_('%d outgoing bookmarks') % len(diff))
5536 t.append(_('%d outgoing bookmarks') % len(diff))
5542
5537
5543 if t:
5538 if t:
5544 # i18n: column positioning for "hg summary"
5539 # i18n: column positioning for "hg summary"
5545 ui.write(_('remote: %s\n') % (', '.join(t)))
5540 ui.write(_('remote: %s\n') % (', '.join(t)))
5546 else:
5541 else:
5547 # i18n: column positioning for "hg summary"
5542 # i18n: column positioning for "hg summary"
5548 ui.status(_('remote: (synced)\n'))
5543 ui.status(_('remote: (synced)\n'))
5549
5544
5550 @command('tag',
5545 @command('tag',
5551 [('f', 'force', None, _('force tag')),
5546 [('f', 'force', None, _('force tag')),
5552 ('l', 'local', None, _('make the tag local')),
5547 ('l', 'local', None, _('make the tag local')),
5553 ('r', 'rev', '', _('revision to tag'), _('REV')),
5548 ('r', 'rev', '', _('revision to tag'), _('REV')),
5554 ('', 'remove', None, _('remove a tag')),
5549 ('', 'remove', None, _('remove a tag')),
5555 # -l/--local is already there, commitopts cannot be used
5550 # -l/--local is already there, commitopts cannot be used
5556 ('e', 'edit', None, _('edit commit message')),
5551 ('e', 'edit', None, _('edit commit message')),
5557 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5552 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5558 ] + commitopts2,
5553 ] + commitopts2,
5559 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5554 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5560 def tag(ui, repo, name1, *names, **opts):
5555 def tag(ui, repo, name1, *names, **opts):
5561 """add one or more tags for the current or given revision
5556 """add one or more tags for the current or given revision
5562
5557
5563 Name a particular revision using <name>.
5558 Name a particular revision using <name>.
5564
5559
5565 Tags are used to name particular revisions of the repository and are
5560 Tags are used to name particular revisions of the repository and are
5566 very useful to compare different revisions, to go back to significant
5561 very useful to compare different revisions, to go back to significant
5567 earlier versions or to mark branch points as releases, etc. Changing
5562 earlier versions or to mark branch points as releases, etc. Changing
5568 an existing tag is normally disallowed; use -f/--force to override.
5563 an existing tag is normally disallowed; use -f/--force to override.
5569
5564
5570 If no revision is given, the parent of the working directory is
5565 If no revision is given, the parent of the working directory is
5571 used.
5566 used.
5572
5567
5573 To facilitate version control, distribution, and merging of tags,
5568 To facilitate version control, distribution, and merging of tags,
5574 they are stored as a file named ".hgtags" which is managed similarly
5569 they are stored as a file named ".hgtags" which is managed similarly
5575 to other project files and can be hand-edited if necessary. This
5570 to other project files and can be hand-edited if necessary. This
5576 also means that tagging creates a new commit. The file
5571 also means that tagging creates a new commit. The file
5577 ".hg/localtags" is used for local tags (not shared among
5572 ".hg/localtags" is used for local tags (not shared among
5578 repositories).
5573 repositories).
5579
5574
5580 Tag commits are usually made at the head of a branch. If the parent
5575 Tag commits are usually made at the head of a branch. If the parent
5581 of the working directory is not a branch head, :hg:`tag` aborts; use
5576 of the working directory is not a branch head, :hg:`tag` aborts; use
5582 -f/--force to force the tag commit to be based on a non-head
5577 -f/--force to force the tag commit to be based on a non-head
5583 changeset.
5578 changeset.
5584
5579
5585 See :hg:`help dates` for a list of formats valid for -d/--date.
5580 See :hg:`help dates` for a list of formats valid for -d/--date.
5586
5581
5587 Since tag names have priority over branch names during revision
5582 Since tag names have priority over branch names during revision
5588 lookup, using an existing branch name as a tag name is discouraged.
5583 lookup, using an existing branch name as a tag name is discouraged.
5589
5584
5590 Returns 0 on success.
5585 Returns 0 on success.
5591 """
5586 """
5592 wlock = lock = None
5587 wlock = lock = None
5593 try:
5588 try:
5594 wlock = repo.wlock()
5589 wlock = repo.wlock()
5595 lock = repo.lock()
5590 lock = repo.lock()
5596 rev_ = "."
5591 rev_ = "."
5597 names = [t.strip() for t in (name1,) + names]
5592 names = [t.strip() for t in (name1,) + names]
5598 if len(names) != len(set(names)):
5593 if len(names) != len(set(names)):
5599 raise util.Abort(_('tag names must be unique'))
5594 raise util.Abort(_('tag names must be unique'))
5600 for n in names:
5595 for n in names:
5601 scmutil.checknewlabel(repo, n, 'tag')
5596 scmutil.checknewlabel(repo, n, 'tag')
5602 if not n:
5597 if not n:
5603 raise util.Abort(_('tag names cannot consist entirely of '
5598 raise util.Abort(_('tag names cannot consist entirely of '
5604 'whitespace'))
5599 'whitespace'))
5605 if opts.get('rev') and opts.get('remove'):
5600 if opts.get('rev') and opts.get('remove'):
5606 raise util.Abort(_("--rev and --remove are incompatible"))
5601 raise util.Abort(_("--rev and --remove are incompatible"))
5607 if opts.get('rev'):
5602 if opts.get('rev'):
5608 rev_ = opts['rev']
5603 rev_ = opts['rev']
5609 message = opts.get('message')
5604 message = opts.get('message')
5610 if opts.get('remove'):
5605 if opts.get('remove'):
5611 expectedtype = opts.get('local') and 'local' or 'global'
5606 expectedtype = opts.get('local') and 'local' or 'global'
5612 for n in names:
5607 for n in names:
5613 if not repo.tagtype(n):
5608 if not repo.tagtype(n):
5614 raise util.Abort(_("tag '%s' does not exist") % n)
5609 raise util.Abort(_("tag '%s' does not exist") % n)
5615 if repo.tagtype(n) != expectedtype:
5610 if repo.tagtype(n) != expectedtype:
5616 if expectedtype == 'global':
5611 if expectedtype == 'global':
5617 raise util.Abort(_("tag '%s' is not a global tag") % n)
5612 raise util.Abort(_("tag '%s' is not a global tag") % n)
5618 else:
5613 else:
5619 raise util.Abort(_("tag '%s' is not a local tag") % n)
5614 raise util.Abort(_("tag '%s' is not a local tag") % n)
5620 rev_ = nullid
5615 rev_ = nullid
5621 if not message:
5616 if not message:
5622 # we don't translate commit messages
5617 # we don't translate commit messages
5623 message = 'Removed tag %s' % ', '.join(names)
5618 message = 'Removed tag %s' % ', '.join(names)
5624 elif not opts.get('force'):
5619 elif not opts.get('force'):
5625 for n in names:
5620 for n in names:
5626 if n in repo.tags():
5621 if n in repo.tags():
5627 raise util.Abort(_("tag '%s' already exists "
5622 raise util.Abort(_("tag '%s' already exists "
5628 "(use -f to force)") % n)
5623 "(use -f to force)") % n)
5629 if not opts.get('local'):
5624 if not opts.get('local'):
5630 p1, p2 = repo.dirstate.parents()
5625 p1, p2 = repo.dirstate.parents()
5631 if p2 != nullid:
5626 if p2 != nullid:
5632 raise util.Abort(_('uncommitted merge'))
5627 raise util.Abort(_('uncommitted merge'))
5633 bheads = repo.branchheads()
5628 bheads = repo.branchheads()
5634 if not opts.get('force') and bheads and p1 not in bheads:
5629 if not opts.get('force') and bheads and p1 not in bheads:
5635 raise util.Abort(_('not at a branch head (use -f to force)'))
5630 raise util.Abort(_('not at a branch head (use -f to force)'))
5636 r = scmutil.revsingle(repo, rev_).node()
5631 r = scmutil.revsingle(repo, rev_).node()
5637
5632
5638 if not message:
5633 if not message:
5639 # we don't translate commit messages
5634 # we don't translate commit messages
5640 message = ('Added tag %s for changeset %s' %
5635 message = ('Added tag %s for changeset %s' %
5641 (', '.join(names), short(r)))
5636 (', '.join(names), short(r)))
5642
5637
5643 date = opts.get('date')
5638 date = opts.get('date')
5644 if date:
5639 if date:
5645 date = util.parsedate(date)
5640 date = util.parsedate(date)
5646
5641
5647 if opts.get('edit'):
5642 if opts.get('edit'):
5648 message = ui.edit(message, ui.username())
5643 message = ui.edit(message, ui.username())
5649
5644
5650 # don't allow tagging the null rev
5645 # don't allow tagging the null rev
5651 if (not opts.get('remove') and
5646 if (not opts.get('remove') and
5652 scmutil.revsingle(repo, rev_).rev() == nullrev):
5647 scmutil.revsingle(repo, rev_).rev() == nullrev):
5653 raise util.Abort(_("cannot tag null revision"))
5648 raise util.Abort(_("cannot tag null revision"))
5654
5649
5655 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5650 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5656 finally:
5651 finally:
5657 release(lock, wlock)
5652 release(lock, wlock)
5658
5653
5659 @command('tags', [], '')
5654 @command('tags', [], '')
5660 def tags(ui, repo, **opts):
5655 def tags(ui, repo, **opts):
5661 """list repository tags
5656 """list repository tags
5662
5657
5663 This lists both regular and local tags. When the -v/--verbose
5658 This lists both regular and local tags. When the -v/--verbose
5664 switch is used, a third column "local" is printed for local tags.
5659 switch is used, a third column "local" is printed for local tags.
5665
5660
5666 Returns 0 on success.
5661 Returns 0 on success.
5667 """
5662 """
5668
5663
5669 fm = ui.formatter('tags', opts)
5664 fm = ui.formatter('tags', opts)
5670 hexfunc = ui.debugflag and hex or short
5665 hexfunc = ui.debugflag and hex or short
5671 tagtype = ""
5666 tagtype = ""
5672
5667
5673 for t, n in reversed(repo.tagslist()):
5668 for t, n in reversed(repo.tagslist()):
5674 hn = hexfunc(n)
5669 hn = hexfunc(n)
5675 label = 'tags.normal'
5670 label = 'tags.normal'
5676 tagtype = ''
5671 tagtype = ''
5677 if repo.tagtype(t) == 'local':
5672 if repo.tagtype(t) == 'local':
5678 label = 'tags.local'
5673 label = 'tags.local'
5679 tagtype = 'local'
5674 tagtype = 'local'
5680
5675
5681 fm.startitem()
5676 fm.startitem()
5682 fm.write('tag', '%s', t, label=label)
5677 fm.write('tag', '%s', t, label=label)
5683 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5678 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5684 fm.condwrite(not ui.quiet, 'rev id', fmt,
5679 fm.condwrite(not ui.quiet, 'rev id', fmt,
5685 repo.changelog.rev(n), hn, label=label)
5680 repo.changelog.rev(n), hn, label=label)
5686 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5681 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5687 tagtype, label=label)
5682 tagtype, label=label)
5688 fm.plain('\n')
5683 fm.plain('\n')
5689 fm.end()
5684 fm.end()
5690
5685
5691 @command('tip',
5686 @command('tip',
5692 [('p', 'patch', None, _('show patch')),
5687 [('p', 'patch', None, _('show patch')),
5693 ('g', 'git', None, _('use git extended diff format')),
5688 ('g', 'git', None, _('use git extended diff format')),
5694 ] + templateopts,
5689 ] + templateopts,
5695 _('[-p] [-g]'))
5690 _('[-p] [-g]'))
5696 def tip(ui, repo, **opts):
5691 def tip(ui, repo, **opts):
5697 """show the tip revision (DEPRECATED)
5692 """show the tip revision (DEPRECATED)
5698
5693
5699 The tip revision (usually just called the tip) is the changeset
5694 The tip revision (usually just called the tip) is the changeset
5700 most recently added to the repository (and therefore the most
5695 most recently added to the repository (and therefore the most
5701 recently changed head).
5696 recently changed head).
5702
5697
5703 If you have just made a commit, that commit will be the tip. If
5698 If you have just made a commit, that commit will be the tip. If
5704 you have just pulled changes from another repository, the tip of
5699 you have just pulled changes from another repository, the tip of
5705 that repository becomes the current tip. The "tip" tag is special
5700 that repository becomes the current tip. The "tip" tag is special
5706 and cannot be renamed or assigned to a different changeset.
5701 and cannot be renamed or assigned to a different changeset.
5707
5702
5708 This command is deprecated, please use :hg:`heads` instead.
5703 This command is deprecated, please use :hg:`heads` instead.
5709
5704
5710 Returns 0 on success.
5705 Returns 0 on success.
5711 """
5706 """
5712 displayer = cmdutil.show_changeset(ui, repo, opts)
5707 displayer = cmdutil.show_changeset(ui, repo, opts)
5713 displayer.show(repo['tip'])
5708 displayer.show(repo['tip'])
5714 displayer.close()
5709 displayer.close()
5715
5710
5716 @command('unbundle',
5711 @command('unbundle',
5717 [('u', 'update', None,
5712 [('u', 'update', None,
5718 _('update to new branch head if changesets were unbundled'))],
5713 _('update to new branch head if changesets were unbundled'))],
5719 _('[-u] FILE...'))
5714 _('[-u] FILE...'))
5720 def unbundle(ui, repo, fname1, *fnames, **opts):
5715 def unbundle(ui, repo, fname1, *fnames, **opts):
5721 """apply one or more changegroup files
5716 """apply one or more changegroup files
5722
5717
5723 Apply one or more compressed changegroup files generated by the
5718 Apply one or more compressed changegroup files generated by the
5724 bundle command.
5719 bundle command.
5725
5720
5726 Returns 0 on success, 1 if an update has unresolved files.
5721 Returns 0 on success, 1 if an update has unresolved files.
5727 """
5722 """
5728 fnames = (fname1,) + fnames
5723 fnames = (fname1,) + fnames
5729
5724
5730 lock = repo.lock()
5725 lock = repo.lock()
5731 wc = repo['.']
5726 wc = repo['.']
5732 try:
5727 try:
5733 for fname in fnames:
5728 for fname in fnames:
5734 f = hg.openpath(ui, fname)
5729 f = hg.openpath(ui, fname)
5735 gen = changegroup.readbundle(f, fname)
5730 gen = changegroup.readbundle(f, fname)
5736 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5731 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5737 finally:
5732 finally:
5738 lock.release()
5733 lock.release()
5739 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5734 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5740 return postincoming(ui, repo, modheads, opts.get('update'), None)
5735 return postincoming(ui, repo, modheads, opts.get('update'), None)
5741
5736
5742 @command('^update|up|checkout|co',
5737 @command('^update|up|checkout|co',
5743 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5738 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5744 ('c', 'check', None,
5739 ('c', 'check', None,
5745 _('update across branches if no uncommitted changes')),
5740 _('update across branches if no uncommitted changes')),
5746 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5741 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5747 ('r', 'rev', '', _('revision'), _('REV'))],
5742 ('r', 'rev', '', _('revision'), _('REV'))],
5748 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5743 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5749 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5744 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5750 """update working directory (or switch revisions)
5745 """update working directory (or switch revisions)
5751
5746
5752 Update the repository's working directory to the specified
5747 Update the repository's working directory to the specified
5753 changeset. If no changeset is specified, update to the tip of the
5748 changeset. If no changeset is specified, update to the tip of the
5754 current named branch and move the current bookmark (see :hg:`help
5749 current named branch and move the current bookmark (see :hg:`help
5755 bookmarks`).
5750 bookmarks`).
5756
5751
5757 Update sets the working directory's parent revision to the specified
5752 Update sets the working directory's parent revision to the specified
5758 changeset (see :hg:`help parents`).
5753 changeset (see :hg:`help parents`).
5759
5754
5760 If the changeset is not a descendant or ancestor of the working
5755 If the changeset is not a descendant or ancestor of the working
5761 directory's parent, the update is aborted. With the -c/--check
5756 directory's parent, the update is aborted. With the -c/--check
5762 option, the working directory is checked for uncommitted changes; if
5757 option, the working directory is checked for uncommitted changes; if
5763 none are found, the working directory is updated to the specified
5758 none are found, the working directory is updated to the specified
5764 changeset.
5759 changeset.
5765
5760
5766 .. container:: verbose
5761 .. container:: verbose
5767
5762
5768 The following rules apply when the working directory contains
5763 The following rules apply when the working directory contains
5769 uncommitted changes:
5764 uncommitted changes:
5770
5765
5771 1. If neither -c/--check nor -C/--clean is specified, and if
5766 1. If neither -c/--check nor -C/--clean is specified, and if
5772 the requested changeset is an ancestor or descendant of
5767 the requested changeset is an ancestor or descendant of
5773 the working directory's parent, the uncommitted changes
5768 the working directory's parent, the uncommitted changes
5774 are merged into the requested changeset and the merged
5769 are merged into the requested changeset and the merged
5775 result is left uncommitted. If the requested changeset is
5770 result is left uncommitted. If the requested changeset is
5776 not an ancestor or descendant (that is, it is on another
5771 not an ancestor or descendant (that is, it is on another
5777 branch), the update is aborted and the uncommitted changes
5772 branch), the update is aborted and the uncommitted changes
5778 are preserved.
5773 are preserved.
5779
5774
5780 2. With the -c/--check option, the update is aborted and the
5775 2. With the -c/--check option, the update is aborted and the
5781 uncommitted changes are preserved.
5776 uncommitted changes are preserved.
5782
5777
5783 3. With the -C/--clean option, uncommitted changes are discarded and
5778 3. With the -C/--clean option, uncommitted changes are discarded and
5784 the working directory is updated to the requested changeset.
5779 the working directory is updated to the requested changeset.
5785
5780
5786 To cancel an uncommitted merge (and lose your changes), use
5781 To cancel an uncommitted merge (and lose your changes), use
5787 :hg:`update --clean .`.
5782 :hg:`update --clean .`.
5788
5783
5789 Use null as the changeset to remove the working directory (like
5784 Use null as the changeset to remove the working directory (like
5790 :hg:`clone -U`).
5785 :hg:`clone -U`).
5791
5786
5792 If you want to revert just one file to an older revision, use
5787 If you want to revert just one file to an older revision, use
5793 :hg:`revert [-r REV] NAME`.
5788 :hg:`revert [-r REV] NAME`.
5794
5789
5795 See :hg:`help dates` for a list of formats valid for -d/--date.
5790 See :hg:`help dates` for a list of formats valid for -d/--date.
5796
5791
5797 Returns 0 on success, 1 if there are unresolved files.
5792 Returns 0 on success, 1 if there are unresolved files.
5798 """
5793 """
5799 if rev and node:
5794 if rev and node:
5800 raise util.Abort(_("please specify just one revision"))
5795 raise util.Abort(_("please specify just one revision"))
5801
5796
5802 if rev is None or rev == '':
5797 if rev is None or rev == '':
5803 rev = node
5798 rev = node
5804
5799
5805 cmdutil.clearunfinished(repo)
5800 cmdutil.clearunfinished(repo)
5806
5801
5807 # with no argument, we also move the current bookmark, if any
5802 # with no argument, we also move the current bookmark, if any
5808 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
5803 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
5809
5804
5810 # if we defined a bookmark, we have to remember the original bookmark name
5805 # if we defined a bookmark, we have to remember the original bookmark name
5811 brev = rev
5806 brev = rev
5812 rev = scmutil.revsingle(repo, rev, rev).rev()
5807 rev = scmutil.revsingle(repo, rev, rev).rev()
5813
5808
5814 if check and clean:
5809 if check and clean:
5815 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5810 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5816
5811
5817 if date:
5812 if date:
5818 if rev is not None:
5813 if rev is not None:
5819 raise util.Abort(_("you can't specify a revision and a date"))
5814 raise util.Abort(_("you can't specify a revision and a date"))
5820 rev = cmdutil.finddate(ui, repo, date)
5815 rev = cmdutil.finddate(ui, repo, date)
5821
5816
5822 if check:
5817 if check:
5823 c = repo[None]
5818 c = repo[None]
5824 if c.dirty(merge=False, branch=False, missing=True):
5819 if c.dirty(merge=False, branch=False, missing=True):
5825 raise util.Abort(_("uncommitted changes"))
5820 raise util.Abort(_("uncommitted changes"))
5826 if rev is None:
5821 if rev is None:
5827 rev = repo[repo[None].branch()].rev()
5822 rev = repo[repo[None].branch()].rev()
5828 mergemod._checkunknown(repo, repo[None], repo[rev])
5823 mergemod._checkunknown(repo, repo[None], repo[rev])
5829
5824
5830 if clean:
5825 if clean:
5831 ret = hg.clean(repo, rev)
5826 ret = hg.clean(repo, rev)
5832 else:
5827 else:
5833 ret = hg.update(repo, rev)
5828 ret = hg.update(repo, rev)
5834
5829
5835 if not ret and movemarkfrom:
5830 if not ret and movemarkfrom:
5836 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5831 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5837 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5832 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5838 elif brev in repo._bookmarks:
5833 elif brev in repo._bookmarks:
5839 bookmarks.setcurrent(repo, brev)
5834 bookmarks.setcurrent(repo, brev)
5840 elif brev:
5835 elif brev:
5841 bookmarks.unsetcurrent(repo)
5836 bookmarks.unsetcurrent(repo)
5842
5837
5843 return ret
5838 return ret
5844
5839
5845 @command('verify', [])
5840 @command('verify', [])
5846 def verify(ui, repo):
5841 def verify(ui, repo):
5847 """verify the integrity of the repository
5842 """verify the integrity of the repository
5848
5843
5849 Verify the integrity of the current repository.
5844 Verify the integrity of the current repository.
5850
5845
5851 This will perform an extensive check of the repository's
5846 This will perform an extensive check of the repository's
5852 integrity, validating the hashes and checksums of each entry in
5847 integrity, validating the hashes and checksums of each entry in
5853 the changelog, manifest, and tracked files, as well as the
5848 the changelog, manifest, and tracked files, as well as the
5854 integrity of their crosslinks and indices.
5849 integrity of their crosslinks and indices.
5855
5850
5856 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
5851 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
5857 for more information about recovery from corruption of the
5852 for more information about recovery from corruption of the
5858 repository.
5853 repository.
5859
5854
5860 Returns 0 on success, 1 if errors are encountered.
5855 Returns 0 on success, 1 if errors are encountered.
5861 """
5856 """
5862 return hg.verify(repo)
5857 return hg.verify(repo)
5863
5858
5864 @command('version', [])
5859 @command('version', [])
5865 def version_(ui):
5860 def version_(ui):
5866 """output version and copyright information"""
5861 """output version and copyright information"""
5867 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5862 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5868 % util.version())
5863 % util.version())
5869 ui.status(_(
5864 ui.status(_(
5870 "(see http://mercurial.selenic.com for more information)\n"
5865 "(see http://mercurial.selenic.com for more information)\n"
5871 "\nCopyright (C) 2005-2014 Matt Mackall and others\n"
5866 "\nCopyright (C) 2005-2014 Matt Mackall and others\n"
5872 "This is free software; see the source for copying conditions. "
5867 "This is free software; see the source for copying conditions. "
5873 "There is NO\nwarranty; "
5868 "There is NO\nwarranty; "
5874 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5869 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5875 ))
5870 ))
5876
5871
5877 norepo = ("clone init version help debugcommands debugcomplete"
5872 norepo = ("clone init version help debugcommands debugcomplete"
5878 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5873 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5879 " debugknown debuggetbundle debugbundle")
5874 " debugknown debuggetbundle debugbundle")
5880 optionalrepo = ("identify paths serve config showconfig debugancestor debugdag"
5875 optionalrepo = ("identify paths serve config showconfig debugancestor debugdag"
5881 " debugdata debugindex debugindexdot debugrevlog")
5876 " debugdata debugindex debugindexdot debugrevlog")
5882 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
5877 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
5883 " remove resolve status debugwalk")
5878 " remove resolve status debugwalk")
@@ -1,932 +1,932 b''
1 # scmutil.py - Mercurial core utility functions
1 # scmutil.py - Mercurial core utility functions
2 #
2 #
3 # Copyright Matt Mackall <mpm@selenic.com>
3 # Copyright 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 i18n import _
8 from i18n import _
9 from mercurial.node import nullrev
9 from mercurial.node import nullrev
10 import util, error, osutil, revset, similar, encoding, phases, parsers
10 import util, error, osutil, revset, similar, encoding, phases, parsers
11 import pathutil
11 import pathutil
12 import match as matchmod
12 import match as matchmod
13 import os, errno, re, glob
13 import os, errno, re, glob
14
14
15 if os.name == 'nt':
15 if os.name == 'nt':
16 import scmwindows as scmplatform
16 import scmwindows as scmplatform
17 else:
17 else:
18 import scmposix as scmplatform
18 import scmposix as scmplatform
19
19
20 systemrcpath = scmplatform.systemrcpath
20 systemrcpath = scmplatform.systemrcpath
21 userrcpath = scmplatform.userrcpath
21 userrcpath = scmplatform.userrcpath
22
22
23 def itersubrepos(ctx1, ctx2):
23 def itersubrepos(ctx1, ctx2):
24 """find subrepos in ctx1 or ctx2"""
24 """find subrepos in ctx1 or ctx2"""
25 # Create a (subpath, ctx) mapping where we prefer subpaths from
25 # Create a (subpath, ctx) mapping where we prefer subpaths from
26 # ctx1. The subpaths from ctx2 are important when the .hgsub file
26 # ctx1. The subpaths from ctx2 are important when the .hgsub file
27 # has been modified (in ctx2) but not yet committed (in ctx1).
27 # has been modified (in ctx2) but not yet committed (in ctx1).
28 subpaths = dict.fromkeys(ctx2.substate, ctx2)
28 subpaths = dict.fromkeys(ctx2.substate, ctx2)
29 subpaths.update(dict.fromkeys(ctx1.substate, ctx1))
29 subpaths.update(dict.fromkeys(ctx1.substate, ctx1))
30 for subpath, ctx in sorted(subpaths.iteritems()):
30 for subpath, ctx in sorted(subpaths.iteritems()):
31 yield subpath, ctx.sub(subpath)
31 yield subpath, ctx.sub(subpath)
32
32
33 def nochangesfound(ui, repo, excluded=None):
33 def nochangesfound(ui, repo, excluded=None):
34 '''Report no changes for push/pull, excluded is None or a list of
34 '''Report no changes for push/pull, excluded is None or a list of
35 nodes excluded from the push/pull.
35 nodes excluded from the push/pull.
36 '''
36 '''
37 secretlist = []
37 secretlist = []
38 if excluded:
38 if excluded:
39 for n in excluded:
39 for n in excluded:
40 if n not in repo:
40 if n not in repo:
41 # discovery should not have included the filtered revision,
41 # discovery should not have included the filtered revision,
42 # we have to explicitly exclude it until discovery is cleanup.
42 # we have to explicitly exclude it until discovery is cleanup.
43 continue
43 continue
44 ctx = repo[n]
44 ctx = repo[n]
45 if ctx.phase() >= phases.secret and not ctx.extinct():
45 if ctx.phase() >= phases.secret and not ctx.extinct():
46 secretlist.append(n)
46 secretlist.append(n)
47
47
48 if secretlist:
48 if secretlist:
49 ui.status(_("no changes found (ignored %d secret changesets)\n")
49 ui.status(_("no changes found (ignored %d secret changesets)\n")
50 % len(secretlist))
50 % len(secretlist))
51 else:
51 else:
52 ui.status(_("no changes found\n"))
52 ui.status(_("no changes found\n"))
53
53
54 def checknewlabel(repo, lbl, kind):
54 def checknewlabel(repo, lbl, kind):
55 # Do not use the "kind" parameter in ui output.
55 # Do not use the "kind" parameter in ui output.
56 # It makes strings difficult to translate.
56 # It makes strings difficult to translate.
57 if lbl in ['tip', '.', 'null']:
57 if lbl in ['tip', '.', 'null']:
58 raise util.Abort(_("the name '%s' is reserved") % lbl)
58 raise util.Abort(_("the name '%s' is reserved") % lbl)
59 for c in (':', '\0', '\n', '\r'):
59 for c in (':', '\0', '\n', '\r'):
60 if c in lbl:
60 if c in lbl:
61 raise util.Abort(_("%r cannot be used in a name") % c)
61 raise util.Abort(_("%r cannot be used in a name") % c)
62 try:
62 try:
63 int(lbl)
63 int(lbl)
64 raise util.Abort(_("cannot use an integer as a name"))
64 raise util.Abort(_("cannot use an integer as a name"))
65 except ValueError:
65 except ValueError:
66 pass
66 pass
67
67
68 def checkfilename(f):
68 def checkfilename(f):
69 '''Check that the filename f is an acceptable filename for a tracked file'''
69 '''Check that the filename f is an acceptable filename for a tracked file'''
70 if '\r' in f or '\n' in f:
70 if '\r' in f or '\n' in f:
71 raise util.Abort(_("'\\n' and '\\r' disallowed in filenames: %r") % f)
71 raise util.Abort(_("'\\n' and '\\r' disallowed in filenames: %r") % f)
72
72
73 def checkportable(ui, f):
73 def checkportable(ui, f):
74 '''Check if filename f is portable and warn or abort depending on config'''
74 '''Check if filename f is portable and warn or abort depending on config'''
75 checkfilename(f)
75 checkfilename(f)
76 abort, warn = checkportabilityalert(ui)
76 abort, warn = checkportabilityalert(ui)
77 if abort or warn:
77 if abort or warn:
78 msg = util.checkwinfilename(f)
78 msg = util.checkwinfilename(f)
79 if msg:
79 if msg:
80 msg = "%s: %r" % (msg, f)
80 msg = "%s: %r" % (msg, f)
81 if abort:
81 if abort:
82 raise util.Abort(msg)
82 raise util.Abort(msg)
83 ui.warn(_("warning: %s\n") % msg)
83 ui.warn(_("warning: %s\n") % msg)
84
84
85 def checkportabilityalert(ui):
85 def checkportabilityalert(ui):
86 '''check if the user's config requests nothing, a warning, or abort for
86 '''check if the user's config requests nothing, a warning, or abort for
87 non-portable filenames'''
87 non-portable filenames'''
88 val = ui.config('ui', 'portablefilenames', 'warn')
88 val = ui.config('ui', 'portablefilenames', 'warn')
89 lval = val.lower()
89 lval = val.lower()
90 bval = util.parsebool(val)
90 bval = util.parsebool(val)
91 abort = os.name == 'nt' or lval == 'abort'
91 abort = os.name == 'nt' or lval == 'abort'
92 warn = bval or lval == 'warn'
92 warn = bval or lval == 'warn'
93 if bval is None and not (warn or abort or lval == 'ignore'):
93 if bval is None and not (warn or abort or lval == 'ignore'):
94 raise error.ConfigError(
94 raise error.ConfigError(
95 _("ui.portablefilenames value is invalid ('%s')") % val)
95 _("ui.portablefilenames value is invalid ('%s')") % val)
96 return abort, warn
96 return abort, warn
97
97
98 class casecollisionauditor(object):
98 class casecollisionauditor(object):
99 def __init__(self, ui, abort, dirstate):
99 def __init__(self, ui, abort, dirstate):
100 self._ui = ui
100 self._ui = ui
101 self._abort = abort
101 self._abort = abort
102 allfiles = '\0'.join(dirstate._map)
102 allfiles = '\0'.join(dirstate._map)
103 self._loweredfiles = set(encoding.lower(allfiles).split('\0'))
103 self._loweredfiles = set(encoding.lower(allfiles).split('\0'))
104 self._dirstate = dirstate
104 self._dirstate = dirstate
105 # The purpose of _newfiles is so that we don't complain about
105 # The purpose of _newfiles is so that we don't complain about
106 # case collisions if someone were to call this object with the
106 # case collisions if someone were to call this object with the
107 # same filename twice.
107 # same filename twice.
108 self._newfiles = set()
108 self._newfiles = set()
109
109
110 def __call__(self, f):
110 def __call__(self, f):
111 if f in self._newfiles:
111 if f in self._newfiles:
112 return
112 return
113 fl = encoding.lower(f)
113 fl = encoding.lower(f)
114 if fl in self._loweredfiles and f not in self._dirstate:
114 if fl in self._loweredfiles and f not in self._dirstate:
115 msg = _('possible case-folding collision for %s') % f
115 msg = _('possible case-folding collision for %s') % f
116 if self._abort:
116 if self._abort:
117 raise util.Abort(msg)
117 raise util.Abort(msg)
118 self._ui.warn(_("warning: %s\n") % msg)
118 self._ui.warn(_("warning: %s\n") % msg)
119 self._loweredfiles.add(fl)
119 self._loweredfiles.add(fl)
120 self._newfiles.add(f)
120 self._newfiles.add(f)
121
121
122 class abstractvfs(object):
122 class abstractvfs(object):
123 """Abstract base class; cannot be instantiated"""
123 """Abstract base class; cannot be instantiated"""
124
124
125 def __init__(self, *args, **kwargs):
125 def __init__(self, *args, **kwargs):
126 '''Prevent instantiation; don't call this from subclasses.'''
126 '''Prevent instantiation; don't call this from subclasses.'''
127 raise NotImplementedError('attempted instantiating ' + str(type(self)))
127 raise NotImplementedError('attempted instantiating ' + str(type(self)))
128
128
129 def tryread(self, path):
129 def tryread(self, path):
130 '''gracefully return an empty string for missing files'''
130 '''gracefully return an empty string for missing files'''
131 try:
131 try:
132 return self.read(path)
132 return self.read(path)
133 except IOError, inst:
133 except IOError, inst:
134 if inst.errno != errno.ENOENT:
134 if inst.errno != errno.ENOENT:
135 raise
135 raise
136 return ""
136 return ""
137
137
138 def open(self, path, mode="r", text=False, atomictemp=False):
138 def open(self, path, mode="r", text=False, atomictemp=False):
139 self.open = self.__call__
139 self.open = self.__call__
140 return self.__call__(path, mode, text, atomictemp)
140 return self.__call__(path, mode, text, atomictemp)
141
141
142 def read(self, path):
142 def read(self, path):
143 fp = self(path, 'rb')
143 fp = self(path, 'rb')
144 try:
144 try:
145 return fp.read()
145 return fp.read()
146 finally:
146 finally:
147 fp.close()
147 fp.close()
148
148
149 def write(self, path, data):
149 def write(self, path, data):
150 fp = self(path, 'wb')
150 fp = self(path, 'wb')
151 try:
151 try:
152 return fp.write(data)
152 return fp.write(data)
153 finally:
153 finally:
154 fp.close()
154 fp.close()
155
155
156 def append(self, path, data):
156 def append(self, path, data):
157 fp = self(path, 'ab')
157 fp = self(path, 'ab')
158 try:
158 try:
159 return fp.write(data)
159 return fp.write(data)
160 finally:
160 finally:
161 fp.close()
161 fp.close()
162
162
163 def chmod(self, path, mode):
163 def chmod(self, path, mode):
164 return os.chmod(self.join(path), mode)
164 return os.chmod(self.join(path), mode)
165
165
166 def exists(self, path=None):
166 def exists(self, path=None):
167 return os.path.exists(self.join(path))
167 return os.path.exists(self.join(path))
168
168
169 def fstat(self, fp):
169 def fstat(self, fp):
170 return util.fstat(fp)
170 return util.fstat(fp)
171
171
172 def isdir(self, path=None):
172 def isdir(self, path=None):
173 return os.path.isdir(self.join(path))
173 return os.path.isdir(self.join(path))
174
174
175 def isfile(self, path=None):
175 def isfile(self, path=None):
176 return os.path.isfile(self.join(path))
176 return os.path.isfile(self.join(path))
177
177
178 def islink(self, path=None):
178 def islink(self, path=None):
179 return os.path.islink(self.join(path))
179 return os.path.islink(self.join(path))
180
180
181 def lstat(self, path=None):
181 def lstat(self, path=None):
182 return os.lstat(self.join(path))
182 return os.lstat(self.join(path))
183
183
184 def makedir(self, path=None, notindexed=True):
184 def makedir(self, path=None, notindexed=True):
185 return util.makedir(self.join(path), notindexed)
185 return util.makedir(self.join(path), notindexed)
186
186
187 def makedirs(self, path=None, mode=None):
187 def makedirs(self, path=None, mode=None):
188 return util.makedirs(self.join(path), mode)
188 return util.makedirs(self.join(path), mode)
189
189
190 def makelock(self, info, path):
190 def makelock(self, info, path):
191 return util.makelock(info, self.join(path))
191 return util.makelock(info, self.join(path))
192
192
193 def mkdir(self, path=None):
193 def mkdir(self, path=None):
194 return os.mkdir(self.join(path))
194 return os.mkdir(self.join(path))
195
195
196 def readdir(self, path=None, stat=None, skip=None):
196 def readdir(self, path=None, stat=None, skip=None):
197 return osutil.listdir(self.join(path), stat, skip)
197 return osutil.listdir(self.join(path), stat, skip)
198
198
199 def readlock(self, path):
199 def readlock(self, path):
200 return util.readlock(self.join(path))
200 return util.readlock(self.join(path))
201
201
202 def rename(self, src, dst):
202 def rename(self, src, dst):
203 return util.rename(self.join(src), self.join(dst))
203 return util.rename(self.join(src), self.join(dst))
204
204
205 def readlink(self, path):
205 def readlink(self, path):
206 return os.readlink(self.join(path))
206 return os.readlink(self.join(path))
207
207
208 def setflags(self, path, l, x):
208 def setflags(self, path, l, x):
209 return util.setflags(self.join(path), l, x)
209 return util.setflags(self.join(path), l, x)
210
210
211 def stat(self, path=None):
211 def stat(self, path=None):
212 return os.stat(self.join(path))
212 return os.stat(self.join(path))
213
213
214 def unlink(self, path=None):
214 def unlink(self, path=None):
215 return util.unlink(self.join(path))
215 return util.unlink(self.join(path))
216
216
217 def utime(self, path=None, t=None):
217 def utime(self, path=None, t=None):
218 return os.utime(self.join(path), t)
218 return os.utime(self.join(path), t)
219
219
220 class vfs(abstractvfs):
220 class vfs(abstractvfs):
221 '''Operate files relative to a base directory
221 '''Operate files relative to a base directory
222
222
223 This class is used to hide the details of COW semantics and
223 This class is used to hide the details of COW semantics and
224 remote file access from higher level code.
224 remote file access from higher level code.
225 '''
225 '''
226 def __init__(self, base, audit=True, expandpath=False, realpath=False):
226 def __init__(self, base, audit=True, expandpath=False, realpath=False):
227 if expandpath:
227 if expandpath:
228 base = util.expandpath(base)
228 base = util.expandpath(base)
229 if realpath:
229 if realpath:
230 base = os.path.realpath(base)
230 base = os.path.realpath(base)
231 self.base = base
231 self.base = base
232 self._setmustaudit(audit)
232 self._setmustaudit(audit)
233 self.createmode = None
233 self.createmode = None
234 self._trustnlink = None
234 self._trustnlink = None
235
235
236 def _getmustaudit(self):
236 def _getmustaudit(self):
237 return self._audit
237 return self._audit
238
238
239 def _setmustaudit(self, onoff):
239 def _setmustaudit(self, onoff):
240 self._audit = onoff
240 self._audit = onoff
241 if onoff:
241 if onoff:
242 self.audit = pathutil.pathauditor(self.base)
242 self.audit = pathutil.pathauditor(self.base)
243 else:
243 else:
244 self.audit = util.always
244 self.audit = util.always
245
245
246 mustaudit = property(_getmustaudit, _setmustaudit)
246 mustaudit = property(_getmustaudit, _setmustaudit)
247
247
248 @util.propertycache
248 @util.propertycache
249 def _cansymlink(self):
249 def _cansymlink(self):
250 return util.checklink(self.base)
250 return util.checklink(self.base)
251
251
252 @util.propertycache
252 @util.propertycache
253 def _chmod(self):
253 def _chmod(self):
254 return util.checkexec(self.base)
254 return util.checkexec(self.base)
255
255
256 def _fixfilemode(self, name):
256 def _fixfilemode(self, name):
257 if self.createmode is None or not self._chmod:
257 if self.createmode is None or not self._chmod:
258 return
258 return
259 os.chmod(name, self.createmode & 0666)
259 os.chmod(name, self.createmode & 0666)
260
260
261 def __call__(self, path, mode="r", text=False, atomictemp=False):
261 def __call__(self, path, mode="r", text=False, atomictemp=False):
262 if self._audit:
262 if self._audit:
263 r = util.checkosfilename(path)
263 r = util.checkosfilename(path)
264 if r:
264 if r:
265 raise util.Abort("%s: %r" % (r, path))
265 raise util.Abort("%s: %r" % (r, path))
266 self.audit(path)
266 self.audit(path)
267 f = self.join(path)
267 f = self.join(path)
268
268
269 if not text and "b" not in mode:
269 if not text and "b" not in mode:
270 mode += "b" # for that other OS
270 mode += "b" # for that other OS
271
271
272 nlink = -1
272 nlink = -1
273 if mode not in ('r', 'rb'):
273 if mode not in ('r', 'rb'):
274 dirname, basename = util.split(f)
274 dirname, basename = util.split(f)
275 # If basename is empty, then the path is malformed because it points
275 # If basename is empty, then the path is malformed because it points
276 # to a directory. Let the posixfile() call below raise IOError.
276 # to a directory. Let the posixfile() call below raise IOError.
277 if basename:
277 if basename:
278 if atomictemp:
278 if atomictemp:
279 util.ensuredirs(dirname, self.createmode)
279 util.ensuredirs(dirname, self.createmode)
280 return util.atomictempfile(f, mode, self.createmode)
280 return util.atomictempfile(f, mode, self.createmode)
281 try:
281 try:
282 if 'w' in mode:
282 if 'w' in mode:
283 util.unlink(f)
283 util.unlink(f)
284 nlink = 0
284 nlink = 0
285 else:
285 else:
286 # nlinks() may behave differently for files on Windows
286 # nlinks() may behave differently for files on Windows
287 # shares if the file is open.
287 # shares if the file is open.
288 fd = util.posixfile(f)
288 fd = util.posixfile(f)
289 nlink = util.nlinks(f)
289 nlink = util.nlinks(f)
290 if nlink < 1:
290 if nlink < 1:
291 nlink = 2 # force mktempcopy (issue1922)
291 nlink = 2 # force mktempcopy (issue1922)
292 fd.close()
292 fd.close()
293 except (OSError, IOError), e:
293 except (OSError, IOError), e:
294 if e.errno != errno.ENOENT:
294 if e.errno != errno.ENOENT:
295 raise
295 raise
296 nlink = 0
296 nlink = 0
297 util.ensuredirs(dirname, self.createmode)
297 util.ensuredirs(dirname, self.createmode)
298 if nlink > 0:
298 if nlink > 0:
299 if self._trustnlink is None:
299 if self._trustnlink is None:
300 self._trustnlink = nlink > 1 or util.checknlink(f)
300 self._trustnlink = nlink > 1 or util.checknlink(f)
301 if nlink > 1 or not self._trustnlink:
301 if nlink > 1 or not self._trustnlink:
302 util.rename(util.mktempcopy(f), f)
302 util.rename(util.mktempcopy(f), f)
303 fp = util.posixfile(f, mode)
303 fp = util.posixfile(f, mode)
304 if nlink == 0:
304 if nlink == 0:
305 self._fixfilemode(f)
305 self._fixfilemode(f)
306 return fp
306 return fp
307
307
308 def symlink(self, src, dst):
308 def symlink(self, src, dst):
309 self.audit(dst)
309 self.audit(dst)
310 linkname = self.join(dst)
310 linkname = self.join(dst)
311 try:
311 try:
312 os.unlink(linkname)
312 os.unlink(linkname)
313 except OSError:
313 except OSError:
314 pass
314 pass
315
315
316 util.ensuredirs(os.path.dirname(linkname), self.createmode)
316 util.ensuredirs(os.path.dirname(linkname), self.createmode)
317
317
318 if self._cansymlink:
318 if self._cansymlink:
319 try:
319 try:
320 os.symlink(src, linkname)
320 os.symlink(src, linkname)
321 except OSError, err:
321 except OSError, err:
322 raise OSError(err.errno, _('could not symlink to %r: %s') %
322 raise OSError(err.errno, _('could not symlink to %r: %s') %
323 (src, err.strerror), linkname)
323 (src, err.strerror), linkname)
324 else:
324 else:
325 self.write(dst, src)
325 self.write(dst, src)
326
326
327 def join(self, path):
327 def join(self, path):
328 if path:
328 if path:
329 return os.path.join(self.base, path)
329 return os.path.join(self.base, path)
330 else:
330 else:
331 return self.base
331 return self.base
332
332
333 opener = vfs
333 opener = vfs
334
334
335 class auditvfs(object):
335 class auditvfs(object):
336 def __init__(self, vfs):
336 def __init__(self, vfs):
337 self.vfs = vfs
337 self.vfs = vfs
338
338
339 def _getmustaudit(self):
339 def _getmustaudit(self):
340 return self.vfs.mustaudit
340 return self.vfs.mustaudit
341
341
342 def _setmustaudit(self, onoff):
342 def _setmustaudit(self, onoff):
343 self.vfs.mustaudit = onoff
343 self.vfs.mustaudit = onoff
344
344
345 mustaudit = property(_getmustaudit, _setmustaudit)
345 mustaudit = property(_getmustaudit, _setmustaudit)
346
346
347 class filtervfs(abstractvfs, auditvfs):
347 class filtervfs(abstractvfs, auditvfs):
348 '''Wrapper vfs for filtering filenames with a function.'''
348 '''Wrapper vfs for filtering filenames with a function.'''
349
349
350 def __init__(self, vfs, filter):
350 def __init__(self, vfs, filter):
351 auditvfs.__init__(self, vfs)
351 auditvfs.__init__(self, vfs)
352 self._filter = filter
352 self._filter = filter
353
353
354 def __call__(self, path, *args, **kwargs):
354 def __call__(self, path, *args, **kwargs):
355 return self.vfs(self._filter(path), *args, **kwargs)
355 return self.vfs(self._filter(path), *args, **kwargs)
356
356
357 def join(self, path):
357 def join(self, path):
358 if path:
358 if path:
359 return self.vfs.join(self._filter(path))
359 return self.vfs.join(self._filter(path))
360 else:
360 else:
361 return self.vfs.join(path)
361 return self.vfs.join(path)
362
362
363 filteropener = filtervfs
363 filteropener = filtervfs
364
364
365 class readonlyvfs(abstractvfs, auditvfs):
365 class readonlyvfs(abstractvfs, auditvfs):
366 '''Wrapper vfs preventing any writing.'''
366 '''Wrapper vfs preventing any writing.'''
367
367
368 def __init__(self, vfs):
368 def __init__(self, vfs):
369 auditvfs.__init__(self, vfs)
369 auditvfs.__init__(self, vfs)
370
370
371 def __call__(self, path, mode='r', *args, **kw):
371 def __call__(self, path, mode='r', *args, **kw):
372 if mode not in ('r', 'rb'):
372 if mode not in ('r', 'rb'):
373 raise util.Abort('this vfs is read only')
373 raise util.Abort('this vfs is read only')
374 return self.vfs(path, mode, *args, **kw)
374 return self.vfs(path, mode, *args, **kw)
375
375
376
376
377 def walkrepos(path, followsym=False, seen_dirs=None, recurse=False):
377 def walkrepos(path, followsym=False, seen_dirs=None, recurse=False):
378 '''yield every hg repository under path, always recursively.
378 '''yield every hg repository under path, always recursively.
379 The recurse flag will only control recursion into repo working dirs'''
379 The recurse flag will only control recursion into repo working dirs'''
380 def errhandler(err):
380 def errhandler(err):
381 if err.filename == path:
381 if err.filename == path:
382 raise err
382 raise err
383 samestat = getattr(os.path, 'samestat', None)
383 samestat = getattr(os.path, 'samestat', None)
384 if followsym and samestat is not None:
384 if followsym and samestat is not None:
385 def adddir(dirlst, dirname):
385 def adddir(dirlst, dirname):
386 match = False
386 match = False
387 dirstat = os.stat(dirname)
387 dirstat = os.stat(dirname)
388 for lstdirstat in dirlst:
388 for lstdirstat in dirlst:
389 if samestat(dirstat, lstdirstat):
389 if samestat(dirstat, lstdirstat):
390 match = True
390 match = True
391 break
391 break
392 if not match:
392 if not match:
393 dirlst.append(dirstat)
393 dirlst.append(dirstat)
394 return not match
394 return not match
395 else:
395 else:
396 followsym = False
396 followsym = False
397
397
398 if (seen_dirs is None) and followsym:
398 if (seen_dirs is None) and followsym:
399 seen_dirs = []
399 seen_dirs = []
400 adddir(seen_dirs, path)
400 adddir(seen_dirs, path)
401 for root, dirs, files in os.walk(path, topdown=True, onerror=errhandler):
401 for root, dirs, files in os.walk(path, topdown=True, onerror=errhandler):
402 dirs.sort()
402 dirs.sort()
403 if '.hg' in dirs:
403 if '.hg' in dirs:
404 yield root # found a repository
404 yield root # found a repository
405 qroot = os.path.join(root, '.hg', 'patches')
405 qroot = os.path.join(root, '.hg', 'patches')
406 if os.path.isdir(os.path.join(qroot, '.hg')):
406 if os.path.isdir(os.path.join(qroot, '.hg')):
407 yield qroot # we have a patch queue repo here
407 yield qroot # we have a patch queue repo here
408 if recurse:
408 if recurse:
409 # avoid recursing inside the .hg directory
409 # avoid recursing inside the .hg directory
410 dirs.remove('.hg')
410 dirs.remove('.hg')
411 else:
411 else:
412 dirs[:] = [] # don't descend further
412 dirs[:] = [] # don't descend further
413 elif followsym:
413 elif followsym:
414 newdirs = []
414 newdirs = []
415 for d in dirs:
415 for d in dirs:
416 fname = os.path.join(root, d)
416 fname = os.path.join(root, d)
417 if adddir(seen_dirs, fname):
417 if adddir(seen_dirs, fname):
418 if os.path.islink(fname):
418 if os.path.islink(fname):
419 for hgname in walkrepos(fname, True, seen_dirs):
419 for hgname in walkrepos(fname, True, seen_dirs):
420 yield hgname
420 yield hgname
421 else:
421 else:
422 newdirs.append(d)
422 newdirs.append(d)
423 dirs[:] = newdirs
423 dirs[:] = newdirs
424
424
425 def osrcpath():
425 def osrcpath():
426 '''return default os-specific hgrc search path'''
426 '''return default os-specific hgrc search path'''
427 path = systemrcpath()
427 path = systemrcpath()
428 path.extend(userrcpath())
428 path.extend(userrcpath())
429 path = [os.path.normpath(f) for f in path]
429 path = [os.path.normpath(f) for f in path]
430 return path
430 return path
431
431
432 _rcpath = None
432 _rcpath = None
433
433
434 def rcpath():
434 def rcpath():
435 '''return hgrc search path. if env var HGRCPATH is set, use it.
435 '''return hgrc search path. if env var HGRCPATH is set, use it.
436 for each item in path, if directory, use files ending in .rc,
436 for each item in path, if directory, use files ending in .rc,
437 else use item.
437 else use item.
438 make HGRCPATH empty to only look in .hg/hgrc of current repo.
438 make HGRCPATH empty to only look in .hg/hgrc of current repo.
439 if no HGRCPATH, use default os-specific path.'''
439 if no HGRCPATH, use default os-specific path.'''
440 global _rcpath
440 global _rcpath
441 if _rcpath is None:
441 if _rcpath is None:
442 if 'HGRCPATH' in os.environ:
442 if 'HGRCPATH' in os.environ:
443 _rcpath = []
443 _rcpath = []
444 for p in os.environ['HGRCPATH'].split(os.pathsep):
444 for p in os.environ['HGRCPATH'].split(os.pathsep):
445 if not p:
445 if not p:
446 continue
446 continue
447 p = util.expandpath(p)
447 p = util.expandpath(p)
448 if os.path.isdir(p):
448 if os.path.isdir(p):
449 for f, kind in osutil.listdir(p):
449 for f, kind in osutil.listdir(p):
450 if f.endswith('.rc'):
450 if f.endswith('.rc'):
451 _rcpath.append(os.path.join(p, f))
451 _rcpath.append(os.path.join(p, f))
452 else:
452 else:
453 _rcpath.append(p)
453 _rcpath.append(p)
454 else:
454 else:
455 _rcpath = osrcpath()
455 _rcpath = osrcpath()
456 return _rcpath
456 return _rcpath
457
457
458 def revsingle(repo, revspec, default='.'):
458 def revsingle(repo, revspec, default='.'):
459 if not revspec and revspec != 0:
459 if not revspec and revspec != 0:
460 return repo[default]
460 return repo[default]
461
461
462 l = revrange(repo, [revspec])
462 l = revrange(repo, [revspec])
463 if len(l) < 1:
463 if len(l) < 1:
464 raise util.Abort(_('empty revision set'))
464 raise util.Abort(_('empty revision set'))
465 return repo[l[-1]]
465 return repo[l[-1]]
466
466
467 def revpair(repo, revs):
467 def revpair(repo, revs):
468 if not revs:
468 if not revs:
469 return repo.dirstate.p1(), None
469 return repo.dirstate.p1(), None
470
470
471 l = revrange(repo, revs)
471 l = revrange(repo, revs)
472
472
473 if len(l) == 0:
473 if len(l) == 0:
474 if revs:
474 if revs:
475 raise util.Abort(_('empty revision range'))
475 raise util.Abort(_('empty revision range'))
476 return repo.dirstate.p1(), None
476 return repo.dirstate.p1(), None
477
477
478 if len(l) == 1 and len(revs) == 1 and _revrangesep not in revs[0]:
478 if len(l) == 1 and len(revs) == 1 and _revrangesep not in revs[0]:
479 return repo.lookup(l[0]), None
479 return repo.lookup(l[0]), None
480
480
481 return repo.lookup(l[0]), repo.lookup(l[-1])
481 return repo.lookup(l[0]), repo.lookup(l[-1])
482
482
483 _revrangesep = ':'
483 _revrangesep = ':'
484
484
485 def revrange(repo, revs):
485 def revrange(repo, revs):
486 """Yield revision as strings from a list of revision specifications."""
486 """Yield revision as strings from a list of revision specifications."""
487
487
488 def revfix(repo, val, defval):
488 def revfix(repo, val, defval):
489 if not val and val != 0 and defval is not None:
489 if not val and val != 0 and defval is not None:
490 return defval
490 return defval
491 return repo[val].rev()
491 return repo[val].rev()
492
492
493 seen, l = set(), revset.baseset([])
493 seen, l = set(), revset.baseset([])
494 for spec in revs:
494 for spec in revs:
495 if l and not seen:
495 if l and not seen:
496 seen = set(l)
496 seen = set(l)
497 # attempt to parse old-style ranges first to deal with
497 # attempt to parse old-style ranges first to deal with
498 # things like old-tag which contain query metacharacters
498 # things like old-tag which contain query metacharacters
499 try:
499 try:
500 if isinstance(spec, int):
500 if isinstance(spec, int):
501 seen.add(spec)
501 seen.add(spec)
502 l = l + [spec]
502 l = l + [spec]
503 continue
503 continue
504
504
505 if _revrangesep in spec:
505 if _revrangesep in spec:
506 start, end = spec.split(_revrangesep, 1)
506 start, end = spec.split(_revrangesep, 1)
507 start = revfix(repo, start, 0)
507 start = revfix(repo, start, 0)
508 end = revfix(repo, end, len(repo) - 1)
508 end = revfix(repo, end, len(repo) - 1)
509 if end == nullrev and start <= 0:
509 if end == nullrev and start < 0:
510 start = nullrev
510 start = nullrev
511 rangeiter = repo.changelog.revs(start, end)
511 rangeiter = repo.changelog.revs(start, end)
512 if not seen and not l:
512 if not seen and not l:
513 # by far the most common case: revs = ["-1:0"]
513 # by far the most common case: revs = ["-1:0"]
514 l = revset.baseset(rangeiter)
514 l = revset.baseset(rangeiter)
515 # defer syncing seen until next iteration
515 # defer syncing seen until next iteration
516 continue
516 continue
517 newrevs = set(rangeiter)
517 newrevs = set(rangeiter)
518 if seen:
518 if seen:
519 newrevs.difference_update(seen)
519 newrevs.difference_update(seen)
520 seen.update(newrevs)
520 seen.update(newrevs)
521 else:
521 else:
522 seen = newrevs
522 seen = newrevs
523 l = l + sorted(newrevs, reverse=start > end)
523 l = l + sorted(newrevs, reverse=start > end)
524 continue
524 continue
525 elif spec and spec in repo: # single unquoted rev
525 elif spec and spec in repo: # single unquoted rev
526 rev = revfix(repo, spec, None)
526 rev = revfix(repo, spec, None)
527 if rev in seen:
527 if rev in seen:
528 continue
528 continue
529 seen.add(rev)
529 seen.add(rev)
530 l = l + [rev]
530 l = l + [rev]
531 continue
531 continue
532 except error.RepoLookupError:
532 except error.RepoLookupError:
533 pass
533 pass
534
534
535 # fall through to new-style queries if old-style fails
535 # fall through to new-style queries if old-style fails
536 m = revset.match(repo.ui, spec)
536 m = revset.match(repo.ui, spec)
537 if seen or l:
537 if seen or l:
538 dl = [r for r in m(repo, revset.spanset(repo)) if r not in seen]
538 dl = [r for r in m(repo, revset.spanset(repo)) if r not in seen]
539 l = l + dl
539 l = l + dl
540 seen.update(dl)
540 seen.update(dl)
541 else:
541 else:
542 l = m(repo, revset.spanset(repo))
542 l = m(repo, revset.spanset(repo))
543
543
544 return l
544 return l
545
545
546 def expandpats(pats):
546 def expandpats(pats):
547 if not util.expandglobs:
547 if not util.expandglobs:
548 return list(pats)
548 return list(pats)
549 ret = []
549 ret = []
550 for p in pats:
550 for p in pats:
551 kind, name = matchmod._patsplit(p, None)
551 kind, name = matchmod._patsplit(p, None)
552 if kind is None:
552 if kind is None:
553 try:
553 try:
554 globbed = glob.glob(name)
554 globbed = glob.glob(name)
555 except re.error:
555 except re.error:
556 globbed = [name]
556 globbed = [name]
557 if globbed:
557 if globbed:
558 ret.extend(globbed)
558 ret.extend(globbed)
559 continue
559 continue
560 ret.append(p)
560 ret.append(p)
561 return ret
561 return ret
562
562
563 def matchandpats(ctx, pats=[], opts={}, globbed=False, default='relpath'):
563 def matchandpats(ctx, pats=[], opts={}, globbed=False, default='relpath'):
564 if pats == ("",):
564 if pats == ("",):
565 pats = []
565 pats = []
566 if not globbed and default == 'relpath':
566 if not globbed and default == 'relpath':
567 pats = expandpats(pats or [])
567 pats = expandpats(pats or [])
568
568
569 m = ctx.match(pats, opts.get('include'), opts.get('exclude'),
569 m = ctx.match(pats, opts.get('include'), opts.get('exclude'),
570 default)
570 default)
571 def badfn(f, msg):
571 def badfn(f, msg):
572 ctx._repo.ui.warn("%s: %s\n" % (m.rel(f), msg))
572 ctx._repo.ui.warn("%s: %s\n" % (m.rel(f), msg))
573 m.bad = badfn
573 m.bad = badfn
574 return m, pats
574 return m, pats
575
575
576 def match(ctx, pats=[], opts={}, globbed=False, default='relpath'):
576 def match(ctx, pats=[], opts={}, globbed=False, default='relpath'):
577 return matchandpats(ctx, pats, opts, globbed, default)[0]
577 return matchandpats(ctx, pats, opts, globbed, default)[0]
578
578
579 def matchall(repo):
579 def matchall(repo):
580 return matchmod.always(repo.root, repo.getcwd())
580 return matchmod.always(repo.root, repo.getcwd())
581
581
582 def matchfiles(repo, files):
582 def matchfiles(repo, files):
583 return matchmod.exact(repo.root, repo.getcwd(), files)
583 return matchmod.exact(repo.root, repo.getcwd(), files)
584
584
585 def addremove(repo, pats=[], opts={}, dry_run=None, similarity=None):
585 def addremove(repo, pats=[], opts={}, dry_run=None, similarity=None):
586 if dry_run is None:
586 if dry_run is None:
587 dry_run = opts.get('dry_run')
587 dry_run = opts.get('dry_run')
588 if similarity is None:
588 if similarity is None:
589 similarity = float(opts.get('similarity') or 0)
589 similarity = float(opts.get('similarity') or 0)
590 # we'd use status here, except handling of symlinks and ignore is tricky
590 # we'd use status here, except handling of symlinks and ignore is tricky
591 m = match(repo[None], pats, opts)
591 m = match(repo[None], pats, opts)
592 rejected = []
592 rejected = []
593 m.bad = lambda x, y: rejected.append(x)
593 m.bad = lambda x, y: rejected.append(x)
594
594
595 added, unknown, deleted, removed = _interestingfiles(repo, m)
595 added, unknown, deleted, removed = _interestingfiles(repo, m)
596
596
597 unknownset = set(unknown)
597 unknownset = set(unknown)
598 toprint = unknownset.copy()
598 toprint = unknownset.copy()
599 toprint.update(deleted)
599 toprint.update(deleted)
600 for abs in sorted(toprint):
600 for abs in sorted(toprint):
601 if repo.ui.verbose or not m.exact(abs):
601 if repo.ui.verbose or not m.exact(abs):
602 rel = m.rel(abs)
602 rel = m.rel(abs)
603 if abs in unknownset:
603 if abs in unknownset:
604 status = _('adding %s\n') % ((pats and rel) or abs)
604 status = _('adding %s\n') % ((pats and rel) or abs)
605 else:
605 else:
606 status = _('removing %s\n') % ((pats and rel) or abs)
606 status = _('removing %s\n') % ((pats and rel) or abs)
607 repo.ui.status(status)
607 repo.ui.status(status)
608
608
609 renames = _findrenames(repo, m, added + unknown, removed + deleted,
609 renames = _findrenames(repo, m, added + unknown, removed + deleted,
610 similarity)
610 similarity)
611
611
612 if not dry_run:
612 if not dry_run:
613 _markchanges(repo, unknown, deleted, renames)
613 _markchanges(repo, unknown, deleted, renames)
614
614
615 for f in rejected:
615 for f in rejected:
616 if f in m.files():
616 if f in m.files():
617 return 1
617 return 1
618 return 0
618 return 0
619
619
620 def marktouched(repo, files, similarity=0.0):
620 def marktouched(repo, files, similarity=0.0):
621 '''Assert that files have somehow been operated upon. files are relative to
621 '''Assert that files have somehow been operated upon. files are relative to
622 the repo root.'''
622 the repo root.'''
623 m = matchfiles(repo, files)
623 m = matchfiles(repo, files)
624 rejected = []
624 rejected = []
625 m.bad = lambda x, y: rejected.append(x)
625 m.bad = lambda x, y: rejected.append(x)
626
626
627 added, unknown, deleted, removed = _interestingfiles(repo, m)
627 added, unknown, deleted, removed = _interestingfiles(repo, m)
628
628
629 if repo.ui.verbose:
629 if repo.ui.verbose:
630 unknownset = set(unknown)
630 unknownset = set(unknown)
631 toprint = unknownset.copy()
631 toprint = unknownset.copy()
632 toprint.update(deleted)
632 toprint.update(deleted)
633 for abs in sorted(toprint):
633 for abs in sorted(toprint):
634 if abs in unknownset:
634 if abs in unknownset:
635 status = _('adding %s\n') % abs
635 status = _('adding %s\n') % abs
636 else:
636 else:
637 status = _('removing %s\n') % abs
637 status = _('removing %s\n') % abs
638 repo.ui.status(status)
638 repo.ui.status(status)
639
639
640 renames = _findrenames(repo, m, added + unknown, removed + deleted,
640 renames = _findrenames(repo, m, added + unknown, removed + deleted,
641 similarity)
641 similarity)
642
642
643 _markchanges(repo, unknown, deleted, renames)
643 _markchanges(repo, unknown, deleted, renames)
644
644
645 for f in rejected:
645 for f in rejected:
646 if f in m.files():
646 if f in m.files():
647 return 1
647 return 1
648 return 0
648 return 0
649
649
650 def _interestingfiles(repo, matcher):
650 def _interestingfiles(repo, matcher):
651 '''Walk dirstate with matcher, looking for files that addremove would care
651 '''Walk dirstate with matcher, looking for files that addremove would care
652 about.
652 about.
653
653
654 This is different from dirstate.status because it doesn't care about
654 This is different from dirstate.status because it doesn't care about
655 whether files are modified or clean.'''
655 whether files are modified or clean.'''
656 added, unknown, deleted, removed = [], [], [], []
656 added, unknown, deleted, removed = [], [], [], []
657 audit_path = pathutil.pathauditor(repo.root)
657 audit_path = pathutil.pathauditor(repo.root)
658
658
659 ctx = repo[None]
659 ctx = repo[None]
660 dirstate = repo.dirstate
660 dirstate = repo.dirstate
661 walkresults = dirstate.walk(matcher, sorted(ctx.substate), True, False,
661 walkresults = dirstate.walk(matcher, sorted(ctx.substate), True, False,
662 full=False)
662 full=False)
663 for abs, st in walkresults.iteritems():
663 for abs, st in walkresults.iteritems():
664 dstate = dirstate[abs]
664 dstate = dirstate[abs]
665 if dstate == '?' and audit_path.check(abs):
665 if dstate == '?' and audit_path.check(abs):
666 unknown.append(abs)
666 unknown.append(abs)
667 elif dstate != 'r' and not st:
667 elif dstate != 'r' and not st:
668 deleted.append(abs)
668 deleted.append(abs)
669 # for finding renames
669 # for finding renames
670 elif dstate == 'r':
670 elif dstate == 'r':
671 removed.append(abs)
671 removed.append(abs)
672 elif dstate == 'a':
672 elif dstate == 'a':
673 added.append(abs)
673 added.append(abs)
674
674
675 return added, unknown, deleted, removed
675 return added, unknown, deleted, removed
676
676
677 def _findrenames(repo, matcher, added, removed, similarity):
677 def _findrenames(repo, matcher, added, removed, similarity):
678 '''Find renames from removed files to added ones.'''
678 '''Find renames from removed files to added ones.'''
679 renames = {}
679 renames = {}
680 if similarity > 0:
680 if similarity > 0:
681 for old, new, score in similar.findrenames(repo, added, removed,
681 for old, new, score in similar.findrenames(repo, added, removed,
682 similarity):
682 similarity):
683 if (repo.ui.verbose or not matcher.exact(old)
683 if (repo.ui.verbose or not matcher.exact(old)
684 or not matcher.exact(new)):
684 or not matcher.exact(new)):
685 repo.ui.status(_('recording removal of %s as rename to %s '
685 repo.ui.status(_('recording removal of %s as rename to %s '
686 '(%d%% similar)\n') %
686 '(%d%% similar)\n') %
687 (matcher.rel(old), matcher.rel(new),
687 (matcher.rel(old), matcher.rel(new),
688 score * 100))
688 score * 100))
689 renames[new] = old
689 renames[new] = old
690 return renames
690 return renames
691
691
692 def _markchanges(repo, unknown, deleted, renames):
692 def _markchanges(repo, unknown, deleted, renames):
693 '''Marks the files in unknown as added, the files in deleted as removed,
693 '''Marks the files in unknown as added, the files in deleted as removed,
694 and the files in renames as copied.'''
694 and the files in renames as copied.'''
695 wctx = repo[None]
695 wctx = repo[None]
696 wlock = repo.wlock()
696 wlock = repo.wlock()
697 try:
697 try:
698 wctx.forget(deleted)
698 wctx.forget(deleted)
699 wctx.add(unknown)
699 wctx.add(unknown)
700 for new, old in renames.iteritems():
700 for new, old in renames.iteritems():
701 wctx.copy(old, new)
701 wctx.copy(old, new)
702 finally:
702 finally:
703 wlock.release()
703 wlock.release()
704
704
705 def dirstatecopy(ui, repo, wctx, src, dst, dryrun=False, cwd=None):
705 def dirstatecopy(ui, repo, wctx, src, dst, dryrun=False, cwd=None):
706 """Update the dirstate to reflect the intent of copying src to dst. For
706 """Update the dirstate to reflect the intent of copying src to dst. For
707 different reasons it might not end with dst being marked as copied from src.
707 different reasons it might not end with dst being marked as copied from src.
708 """
708 """
709 origsrc = repo.dirstate.copied(src) or src
709 origsrc = repo.dirstate.copied(src) or src
710 if dst == origsrc: # copying back a copy?
710 if dst == origsrc: # copying back a copy?
711 if repo.dirstate[dst] not in 'mn' and not dryrun:
711 if repo.dirstate[dst] not in 'mn' and not dryrun:
712 repo.dirstate.normallookup(dst)
712 repo.dirstate.normallookup(dst)
713 else:
713 else:
714 if repo.dirstate[origsrc] == 'a' and origsrc == src:
714 if repo.dirstate[origsrc] == 'a' and origsrc == src:
715 if not ui.quiet:
715 if not ui.quiet:
716 ui.warn(_("%s has not been committed yet, so no copy "
716 ui.warn(_("%s has not been committed yet, so no copy "
717 "data will be stored for %s.\n")
717 "data will be stored for %s.\n")
718 % (repo.pathto(origsrc, cwd), repo.pathto(dst, cwd)))
718 % (repo.pathto(origsrc, cwd), repo.pathto(dst, cwd)))
719 if repo.dirstate[dst] in '?r' and not dryrun:
719 if repo.dirstate[dst] in '?r' and not dryrun:
720 wctx.add([dst])
720 wctx.add([dst])
721 elif not dryrun:
721 elif not dryrun:
722 wctx.copy(origsrc, dst)
722 wctx.copy(origsrc, dst)
723
723
724 def readrequires(opener, supported):
724 def readrequires(opener, supported):
725 '''Reads and parses .hg/requires and checks if all entries found
725 '''Reads and parses .hg/requires and checks if all entries found
726 are in the list of supported features.'''
726 are in the list of supported features.'''
727 requirements = set(opener.read("requires").splitlines())
727 requirements = set(opener.read("requires").splitlines())
728 missings = []
728 missings = []
729 for r in requirements:
729 for r in requirements:
730 if r not in supported:
730 if r not in supported:
731 if not r or not r[0].isalnum():
731 if not r or not r[0].isalnum():
732 raise error.RequirementError(_(".hg/requires file is corrupt"))
732 raise error.RequirementError(_(".hg/requires file is corrupt"))
733 missings.append(r)
733 missings.append(r)
734 missings.sort()
734 missings.sort()
735 if missings:
735 if missings:
736 raise error.RequirementError(
736 raise error.RequirementError(
737 _("unknown repository format: requires features '%s' (upgrade "
737 _("unknown repository format: requires features '%s' (upgrade "
738 "Mercurial)") % "', '".join(missings))
738 "Mercurial)") % "', '".join(missings))
739 return requirements
739 return requirements
740
740
741 class filecachesubentry(object):
741 class filecachesubentry(object):
742 def __init__(self, path, stat):
742 def __init__(self, path, stat):
743 self.path = path
743 self.path = path
744 self.cachestat = None
744 self.cachestat = None
745 self._cacheable = None
745 self._cacheable = None
746
746
747 if stat:
747 if stat:
748 self.cachestat = filecachesubentry.stat(self.path)
748 self.cachestat = filecachesubentry.stat(self.path)
749
749
750 if self.cachestat:
750 if self.cachestat:
751 self._cacheable = self.cachestat.cacheable()
751 self._cacheable = self.cachestat.cacheable()
752 else:
752 else:
753 # None means we don't know yet
753 # None means we don't know yet
754 self._cacheable = None
754 self._cacheable = None
755
755
756 def refresh(self):
756 def refresh(self):
757 if self.cacheable():
757 if self.cacheable():
758 self.cachestat = filecachesubentry.stat(self.path)
758 self.cachestat = filecachesubentry.stat(self.path)
759
759
760 def cacheable(self):
760 def cacheable(self):
761 if self._cacheable is not None:
761 if self._cacheable is not None:
762 return self._cacheable
762 return self._cacheable
763
763
764 # we don't know yet, assume it is for now
764 # we don't know yet, assume it is for now
765 return True
765 return True
766
766
767 def changed(self):
767 def changed(self):
768 # no point in going further if we can't cache it
768 # no point in going further if we can't cache it
769 if not self.cacheable():
769 if not self.cacheable():
770 return True
770 return True
771
771
772 newstat = filecachesubentry.stat(self.path)
772 newstat = filecachesubentry.stat(self.path)
773
773
774 # we may not know if it's cacheable yet, check again now
774 # we may not know if it's cacheable yet, check again now
775 if newstat and self._cacheable is None:
775 if newstat and self._cacheable is None:
776 self._cacheable = newstat.cacheable()
776 self._cacheable = newstat.cacheable()
777
777
778 # check again
778 # check again
779 if not self._cacheable:
779 if not self._cacheable:
780 return True
780 return True
781
781
782 if self.cachestat != newstat:
782 if self.cachestat != newstat:
783 self.cachestat = newstat
783 self.cachestat = newstat
784 return True
784 return True
785 else:
785 else:
786 return False
786 return False
787
787
788 @staticmethod
788 @staticmethod
789 def stat(path):
789 def stat(path):
790 try:
790 try:
791 return util.cachestat(path)
791 return util.cachestat(path)
792 except OSError, e:
792 except OSError, e:
793 if e.errno != errno.ENOENT:
793 if e.errno != errno.ENOENT:
794 raise
794 raise
795
795
796 class filecacheentry(object):
796 class filecacheentry(object):
797 def __init__(self, paths, stat=True):
797 def __init__(self, paths, stat=True):
798 self._entries = []
798 self._entries = []
799 for path in paths:
799 for path in paths:
800 self._entries.append(filecachesubentry(path, stat))
800 self._entries.append(filecachesubentry(path, stat))
801
801
802 def changed(self):
802 def changed(self):
803 '''true if any entry has changed'''
803 '''true if any entry has changed'''
804 for entry in self._entries:
804 for entry in self._entries:
805 if entry.changed():
805 if entry.changed():
806 return True
806 return True
807 return False
807 return False
808
808
809 def refresh(self):
809 def refresh(self):
810 for entry in self._entries:
810 for entry in self._entries:
811 entry.refresh()
811 entry.refresh()
812
812
813 class filecache(object):
813 class filecache(object):
814 '''A property like decorator that tracks files under .hg/ for updates.
814 '''A property like decorator that tracks files under .hg/ for updates.
815
815
816 Records stat info when called in _filecache.
816 Records stat info when called in _filecache.
817
817
818 On subsequent calls, compares old stat info with new info, and recreates the
818 On subsequent calls, compares old stat info with new info, and recreates the
819 object when any of the files changes, updating the new stat info in
819 object when any of the files changes, updating the new stat info in
820 _filecache.
820 _filecache.
821
821
822 Mercurial either atomic renames or appends for files under .hg,
822 Mercurial either atomic renames or appends for files under .hg,
823 so to ensure the cache is reliable we need the filesystem to be able
823 so to ensure the cache is reliable we need the filesystem to be able
824 to tell us if a file has been replaced. If it can't, we fallback to
824 to tell us if a file has been replaced. If it can't, we fallback to
825 recreating the object on every call (essentially the same behaviour as
825 recreating the object on every call (essentially the same behaviour as
826 propertycache).
826 propertycache).
827
827
828 '''
828 '''
829 def __init__(self, *paths):
829 def __init__(self, *paths):
830 self.paths = paths
830 self.paths = paths
831
831
832 def join(self, obj, fname):
832 def join(self, obj, fname):
833 """Used to compute the runtime path of a cached file.
833 """Used to compute the runtime path of a cached file.
834
834
835 Users should subclass filecache and provide their own version of this
835 Users should subclass filecache and provide their own version of this
836 function to call the appropriate join function on 'obj' (an instance
836 function to call the appropriate join function on 'obj' (an instance
837 of the class that its member function was decorated).
837 of the class that its member function was decorated).
838 """
838 """
839 return obj.join(fname)
839 return obj.join(fname)
840
840
841 def __call__(self, func):
841 def __call__(self, func):
842 self.func = func
842 self.func = func
843 self.name = func.__name__
843 self.name = func.__name__
844 return self
844 return self
845
845
846 def __get__(self, obj, type=None):
846 def __get__(self, obj, type=None):
847 # do we need to check if the file changed?
847 # do we need to check if the file changed?
848 if self.name in obj.__dict__:
848 if self.name in obj.__dict__:
849 assert self.name in obj._filecache, self.name
849 assert self.name in obj._filecache, self.name
850 return obj.__dict__[self.name]
850 return obj.__dict__[self.name]
851
851
852 entry = obj._filecache.get(self.name)
852 entry = obj._filecache.get(self.name)
853
853
854 if entry:
854 if entry:
855 if entry.changed():
855 if entry.changed():
856 entry.obj = self.func(obj)
856 entry.obj = self.func(obj)
857 else:
857 else:
858 paths = [self.join(obj, path) for path in self.paths]
858 paths = [self.join(obj, path) for path in self.paths]
859
859
860 # We stat -before- creating the object so our cache doesn't lie if
860 # We stat -before- creating the object so our cache doesn't lie if
861 # a writer modified between the time we read and stat
861 # a writer modified between the time we read and stat
862 entry = filecacheentry(paths, True)
862 entry = filecacheentry(paths, True)
863 entry.obj = self.func(obj)
863 entry.obj = self.func(obj)
864
864
865 obj._filecache[self.name] = entry
865 obj._filecache[self.name] = entry
866
866
867 obj.__dict__[self.name] = entry.obj
867 obj.__dict__[self.name] = entry.obj
868 return entry.obj
868 return entry.obj
869
869
870 def __set__(self, obj, value):
870 def __set__(self, obj, value):
871 if self.name not in obj._filecache:
871 if self.name not in obj._filecache:
872 # we add an entry for the missing value because X in __dict__
872 # we add an entry for the missing value because X in __dict__
873 # implies X in _filecache
873 # implies X in _filecache
874 paths = [self.join(obj, path) for path in self.paths]
874 paths = [self.join(obj, path) for path in self.paths]
875 ce = filecacheentry(paths, False)
875 ce = filecacheentry(paths, False)
876 obj._filecache[self.name] = ce
876 obj._filecache[self.name] = ce
877 else:
877 else:
878 ce = obj._filecache[self.name]
878 ce = obj._filecache[self.name]
879
879
880 ce.obj = value # update cached copy
880 ce.obj = value # update cached copy
881 obj.__dict__[self.name] = value # update copy returned by obj.x
881 obj.__dict__[self.name] = value # update copy returned by obj.x
882
882
883 def __delete__(self, obj):
883 def __delete__(self, obj):
884 try:
884 try:
885 del obj.__dict__[self.name]
885 del obj.__dict__[self.name]
886 except KeyError:
886 except KeyError:
887 raise AttributeError(self.name)
887 raise AttributeError(self.name)
888
888
889 class dirs(object):
889 class dirs(object):
890 '''a multiset of directory names from a dirstate or manifest'''
890 '''a multiset of directory names from a dirstate or manifest'''
891
891
892 def __init__(self, map, skip=None):
892 def __init__(self, map, skip=None):
893 self._dirs = {}
893 self._dirs = {}
894 addpath = self.addpath
894 addpath = self.addpath
895 if util.safehasattr(map, 'iteritems') and skip is not None:
895 if util.safehasattr(map, 'iteritems') and skip is not None:
896 for f, s in map.iteritems():
896 for f, s in map.iteritems():
897 if s[0] != skip:
897 if s[0] != skip:
898 addpath(f)
898 addpath(f)
899 else:
899 else:
900 for f in map:
900 for f in map:
901 addpath(f)
901 addpath(f)
902
902
903 def addpath(self, path):
903 def addpath(self, path):
904 dirs = self._dirs
904 dirs = self._dirs
905 for base in finddirs(path):
905 for base in finddirs(path):
906 if base in dirs:
906 if base in dirs:
907 dirs[base] += 1
907 dirs[base] += 1
908 return
908 return
909 dirs[base] = 1
909 dirs[base] = 1
910
910
911 def delpath(self, path):
911 def delpath(self, path):
912 dirs = self._dirs
912 dirs = self._dirs
913 for base in finddirs(path):
913 for base in finddirs(path):
914 if dirs[base] > 1:
914 if dirs[base] > 1:
915 dirs[base] -= 1
915 dirs[base] -= 1
916 return
916 return
917 del dirs[base]
917 del dirs[base]
918
918
919 def __iter__(self):
919 def __iter__(self):
920 return self._dirs.iterkeys()
920 return self._dirs.iterkeys()
921
921
922 def __contains__(self, d):
922 def __contains__(self, d):
923 return d in self._dirs
923 return d in self._dirs
924
924
925 if util.safehasattr(parsers, 'dirs'):
925 if util.safehasattr(parsers, 'dirs'):
926 dirs = parsers.dirs
926 dirs = parsers.dirs
927
927
928 def finddirs(path):
928 def finddirs(path):
929 pos = path.rfind('/')
929 pos = path.rfind('/')
930 while pos != -1:
930 while pos != -1:
931 yield path[:pos]
931 yield path[:pos]
932 pos = path.rfind('/', 0, pos)
932 pos = path.rfind('/', 0, pos)
@@ -1,767 +1,778 b''
1 $ hg init
1 $ hg init
2
2
3 Setup:
3 Setup:
4
4
5 $ echo a >> a
5 $ echo a >> a
6 $ hg ci -Am 'base'
6 $ hg ci -Am 'base'
7 adding a
7 adding a
8
8
9 Refuse to amend public csets:
9 Refuse to amend public csets:
10
10
11 $ hg phase -r . -p
11 $ hg phase -r . -p
12 $ hg ci --amend
12 $ hg ci --amend
13 abort: cannot amend public changesets
13 abort: cannot amend public changesets
14 [255]
14 [255]
15 $ hg phase -r . -f -d
15 $ hg phase -r . -f -d
16
16
17 $ echo a >> a
17 $ echo a >> a
18 $ hg ci -Am 'base1'
18 $ hg ci -Am 'base1'
19
19
20 Nothing to amend:
20 Nothing to amend:
21
21
22 $ hg ci --amend
22 $ hg ci --amend
23 nothing changed
23 nothing changed
24 [1]
24 [1]
25
25
26 $ cat >> $HGRCPATH <<EOF
26 $ cat >> $HGRCPATH <<EOF
27 > [hooks]
27 > [hooks]
28 > pretxncommit.foo = sh -c "echo \\"pretxncommit \$HG_NODE\\"; hg id -r \$HG_NODE"
28 > pretxncommit.foo = sh -c "echo \\"pretxncommit \$HG_NODE\\"; hg id -r \$HG_NODE"
29 > EOF
29 > EOF
30
30
31 Amending changeset with changes in working dir:
31 Amending changeset with changes in working dir:
32 (and check that --message does not trigger an editor)
32 (and check that --message does not trigger an editor)
33
33
34 $ echo a >> a
34 $ echo a >> a
35 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit --amend -m 'amend base1'
35 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit --amend -m 'amend base1'
36 pretxncommit 43f1ba15f28a50abf0aae529cf8a16bfced7b149
36 pretxncommit 43f1ba15f28a50abf0aae529cf8a16bfced7b149
37 43f1ba15f28a tip
37 43f1ba15f28a tip
38 saved backup bundle to $TESTTMP/.hg/strip-backup/489edb5b847d-amend-backup.hg (glob)
38 saved backup bundle to $TESTTMP/.hg/strip-backup/489edb5b847d-amend-backup.hg (glob)
39 $ echo 'pretxncommit.foo = ' >> $HGRCPATH
39 $ echo 'pretxncommit.foo = ' >> $HGRCPATH
40 $ hg diff -c .
40 $ hg diff -c .
41 diff -r ad120869acf0 -r 43f1ba15f28a a
41 diff -r ad120869acf0 -r 43f1ba15f28a a
42 --- a/a Thu Jan 01 00:00:00 1970 +0000
42 --- a/a Thu Jan 01 00:00:00 1970 +0000
43 +++ b/a Thu Jan 01 00:00:00 1970 +0000
43 +++ b/a Thu Jan 01 00:00:00 1970 +0000
44 @@ -1,1 +1,3 @@
44 @@ -1,1 +1,3 @@
45 a
45 a
46 +a
46 +a
47 +a
47 +a
48 $ hg log
48 $ hg log
49 changeset: 1:43f1ba15f28a
49 changeset: 1:43f1ba15f28a
50 tag: tip
50 tag: tip
51 user: test
51 user: test
52 date: Thu Jan 01 00:00:00 1970 +0000
52 date: Thu Jan 01 00:00:00 1970 +0000
53 summary: amend base1
53 summary: amend base1
54
54
55 changeset: 0:ad120869acf0
55 changeset: 0:ad120869acf0
56 user: test
56 user: test
57 date: Thu Jan 01 00:00:00 1970 +0000
57 date: Thu Jan 01 00:00:00 1970 +0000
58 summary: base
58 summary: base
59
59
60
60
61 Check proper abort for empty message
61 Check proper abort for empty message
62
62
63 $ cat > editor.sh << '__EOF__'
63 $ cat > editor.sh << '__EOF__'
64 > #!/bin/sh
64 > #!/bin/sh
65 > echo "" > "$1"
65 > echo "" > "$1"
66 > __EOF__
66 > __EOF__
67 $ echo b > b
67 $ echo b > b
68 $ hg add b
68 $ hg add b
69 $ hg summary
69 $ hg summary
70 parent: 1:43f1ba15f28a tip
70 parent: 1:43f1ba15f28a tip
71 amend base1
71 amend base1
72 branch: default
72 branch: default
73 commit: 1 added, 1 unknown
73 commit: 1 added, 1 unknown
74 update: (current)
74 update: (current)
75 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit --amend
75 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit --amend
76 transaction abort!
76 transaction abort!
77 rollback completed
77 rollback completed
78 abort: empty commit message
78 abort: empty commit message
79 [255]
79 [255]
80 $ hg summary
80 $ hg summary
81 parent: 1:43f1ba15f28a tip
81 parent: 1:43f1ba15f28a tip
82 amend base1
82 amend base1
83 branch: default
83 branch: default
84 commit: 1 added, 1 unknown
84 commit: 1 added, 1 unknown
85 update: (current)
85 update: (current)
86
86
87 Add new file:
87 Add new file:
88 $ hg ci --amend -m 'amend base1 new file'
88 $ hg ci --amend -m 'amend base1 new file'
89 saved backup bundle to $TESTTMP/.hg/strip-backup/43f1ba15f28a-amend-backup.hg (glob)
89 saved backup bundle to $TESTTMP/.hg/strip-backup/43f1ba15f28a-amend-backup.hg (glob)
90
90
91 Remove file that was added in amended commit:
91 Remove file that was added in amended commit:
92 (and test logfile option)
92 (and test logfile option)
93 (and test that logfile option do not trigger an editor)
93 (and test that logfile option do not trigger an editor)
94
94
95 $ hg rm b
95 $ hg rm b
96 $ echo 'amend base1 remove new file' > ../logfile
96 $ echo 'amend base1 remove new file' > ../logfile
97 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg ci --amend --logfile ../logfile
97 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg ci --amend --logfile ../logfile
98 saved backup bundle to $TESTTMP/.hg/strip-backup/b8e3cb2b3882-amend-backup.hg (glob)
98 saved backup bundle to $TESTTMP/.hg/strip-backup/b8e3cb2b3882-amend-backup.hg (glob)
99
99
100 $ hg cat b
100 $ hg cat b
101 b: no such file in rev 74609c7f506e
101 b: no such file in rev 74609c7f506e
102 [1]
102 [1]
103
103
104 No changes, just a different message:
104 No changes, just a different message:
105
105
106 $ hg ci -v --amend -m 'no changes, new message'
106 $ hg ci -v --amend -m 'no changes, new message'
107 amending changeset 74609c7f506e
107 amending changeset 74609c7f506e
108 copying changeset 74609c7f506e to ad120869acf0
108 copying changeset 74609c7f506e to ad120869acf0
109 a
109 a
110 stripping amended changeset 74609c7f506e
110 stripping amended changeset 74609c7f506e
111 1 changesets found
111 1 changesets found
112 saved backup bundle to $TESTTMP/.hg/strip-backup/74609c7f506e-amend-backup.hg (glob)
112 saved backup bundle to $TESTTMP/.hg/strip-backup/74609c7f506e-amend-backup.hg (glob)
113 1 changesets found
113 1 changesets found
114 adding branch
114 adding branch
115 adding changesets
115 adding changesets
116 adding manifests
116 adding manifests
117 adding file changes
117 adding file changes
118 added 1 changesets with 1 changes to 1 files
118 added 1 changesets with 1 changes to 1 files
119 committed changeset 1:1cd866679df8
119 committed changeset 1:1cd866679df8
120 $ hg diff -c .
120 $ hg diff -c .
121 diff -r ad120869acf0 -r 1cd866679df8 a
121 diff -r ad120869acf0 -r 1cd866679df8 a
122 --- a/a Thu Jan 01 00:00:00 1970 +0000
122 --- a/a Thu Jan 01 00:00:00 1970 +0000
123 +++ b/a Thu Jan 01 00:00:00 1970 +0000
123 +++ b/a Thu Jan 01 00:00:00 1970 +0000
124 @@ -1,1 +1,3 @@
124 @@ -1,1 +1,3 @@
125 a
125 a
126 +a
126 +a
127 +a
127 +a
128 $ hg log
128 $ hg log
129 changeset: 1:1cd866679df8
129 changeset: 1:1cd866679df8
130 tag: tip
130 tag: tip
131 user: test
131 user: test
132 date: Thu Jan 01 00:00:00 1970 +0000
132 date: Thu Jan 01 00:00:00 1970 +0000
133 summary: no changes, new message
133 summary: no changes, new message
134
134
135 changeset: 0:ad120869acf0
135 changeset: 0:ad120869acf0
136 user: test
136 user: test
137 date: Thu Jan 01 00:00:00 1970 +0000
137 date: Thu Jan 01 00:00:00 1970 +0000
138 summary: base
138 summary: base
139
139
140
140
141 Disable default date on commit so when -d isn't given, the old date is preserved:
141 Disable default date on commit so when -d isn't given, the old date is preserved:
142
142
143 $ echo '[defaults]' >> $HGRCPATH
143 $ echo '[defaults]' >> $HGRCPATH
144 $ echo 'commit=' >> $HGRCPATH
144 $ echo 'commit=' >> $HGRCPATH
145
145
146 Test -u/-d:
146 Test -u/-d:
147
147
148 $ hg ci --amend -u foo -d '1 0'
148 $ hg ci --amend -u foo -d '1 0'
149 saved backup bundle to $TESTTMP/.hg/strip-backup/1cd866679df8-amend-backup.hg (glob)
149 saved backup bundle to $TESTTMP/.hg/strip-backup/1cd866679df8-amend-backup.hg (glob)
150 $ echo a >> a
150 $ echo a >> a
151 $ hg ci --amend -u foo -d '1 0'
151 $ hg ci --amend -u foo -d '1 0'
152 saved backup bundle to $TESTTMP/.hg/strip-backup/780e6f23e03d-amend-backup.hg (glob)
152 saved backup bundle to $TESTTMP/.hg/strip-backup/780e6f23e03d-amend-backup.hg (glob)
153 $ hg log -r .
153 $ hg log -r .
154 changeset: 1:5f357c7560ab
154 changeset: 1:5f357c7560ab
155 tag: tip
155 tag: tip
156 user: foo
156 user: foo
157 date: Thu Jan 01 00:00:01 1970 +0000
157 date: Thu Jan 01 00:00:01 1970 +0000
158 summary: no changes, new message
158 summary: no changes, new message
159
159
160
160
161 Open editor with old commit message if a message isn't given otherwise:
161 Open editor with old commit message if a message isn't given otherwise:
162
162
163 $ cat > editor.sh << '__EOF__'
163 $ cat > editor.sh << '__EOF__'
164 > #!/bin/sh
164 > #!/bin/sh
165 > cat $1
165 > cat $1
166 > echo "another precious commit message" > "$1"
166 > echo "another precious commit message" > "$1"
167 > __EOF__
167 > __EOF__
168 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit --amend -v
168 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit --amend -v
169 amending changeset 5f357c7560ab
169 amending changeset 5f357c7560ab
170 copying changeset 5f357c7560ab to ad120869acf0
170 copying changeset 5f357c7560ab to ad120869acf0
171 no changes, new message
171 no changes, new message
172
172
173
173
174 HG: Enter commit message. Lines beginning with 'HG:' are removed.
174 HG: Enter commit message. Lines beginning with 'HG:' are removed.
175 HG: Leave message empty to abort commit.
175 HG: Leave message empty to abort commit.
176 HG: --
176 HG: --
177 HG: user: foo
177 HG: user: foo
178 HG: branch 'default'
178 HG: branch 'default'
179 HG: changed a
179 HG: changed a
180 a
180 a
181 stripping amended changeset 5f357c7560ab
181 stripping amended changeset 5f357c7560ab
182 1 changesets found
182 1 changesets found
183 saved backup bundle to $TESTTMP/.hg/strip-backup/5f357c7560ab-amend-backup.hg (glob)
183 saved backup bundle to $TESTTMP/.hg/strip-backup/5f357c7560ab-amend-backup.hg (glob)
184 1 changesets found
184 1 changesets found
185 adding branch
185 adding branch
186 adding changesets
186 adding changesets
187 adding manifests
187 adding manifests
188 adding file changes
188 adding file changes
189 added 1 changesets with 1 changes to 1 files
189 added 1 changesets with 1 changes to 1 files
190 committed changeset 1:7ab3bf440b54
190 committed changeset 1:7ab3bf440b54
191
191
192 Same, but with changes in working dir (different code path):
192 Same, but with changes in working dir (different code path):
193
193
194 $ echo a >> a
194 $ echo a >> a
195 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit --amend -v
195 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit --amend -v
196 amending changeset 7ab3bf440b54
196 amending changeset 7ab3bf440b54
197 a
197 a
198 copying changeset a0ea9b1a4c8c to ad120869acf0
198 copying changeset a0ea9b1a4c8c to ad120869acf0
199 another precious commit message
199 another precious commit message
200
200
201
201
202 HG: Enter commit message. Lines beginning with 'HG:' are removed.
202 HG: Enter commit message. Lines beginning with 'HG:' are removed.
203 HG: Leave message empty to abort commit.
203 HG: Leave message empty to abort commit.
204 HG: --
204 HG: --
205 HG: user: foo
205 HG: user: foo
206 HG: branch 'default'
206 HG: branch 'default'
207 HG: changed a
207 HG: changed a
208 a
208 a
209 stripping intermediate changeset a0ea9b1a4c8c
209 stripping intermediate changeset a0ea9b1a4c8c
210 stripping amended changeset 7ab3bf440b54
210 stripping amended changeset 7ab3bf440b54
211 2 changesets found
211 2 changesets found
212 saved backup bundle to $TESTTMP/.hg/strip-backup/7ab3bf440b54-amend-backup.hg (glob)
212 saved backup bundle to $TESTTMP/.hg/strip-backup/7ab3bf440b54-amend-backup.hg (glob)
213 1 changesets found
213 1 changesets found
214 adding branch
214 adding branch
215 adding changesets
215 adding changesets
216 adding manifests
216 adding manifests
217 adding file changes
217 adding file changes
218 added 1 changesets with 1 changes to 1 files
218 added 1 changesets with 1 changes to 1 files
219 committed changeset 1:ea22a388757c
219 committed changeset 1:ea22a388757c
220
220
221 $ rm editor.sh
221 $ rm editor.sh
222 $ hg log -r .
222 $ hg log -r .
223 changeset: 1:ea22a388757c
223 changeset: 1:ea22a388757c
224 tag: tip
224 tag: tip
225 user: foo
225 user: foo
226 date: Thu Jan 01 00:00:01 1970 +0000
226 date: Thu Jan 01 00:00:01 1970 +0000
227 summary: another precious commit message
227 summary: another precious commit message
228
228
229
229
230 Moving bookmarks, preserve active bookmark:
230 Moving bookmarks, preserve active bookmark:
231
231
232 $ hg book book1
232 $ hg book book1
233 $ hg book book2
233 $ hg book book2
234 $ hg ci --amend -m 'move bookmarks'
234 $ hg ci --amend -m 'move bookmarks'
235 saved backup bundle to $TESTTMP/.hg/strip-backup/ea22a388757c-amend-backup.hg (glob)
235 saved backup bundle to $TESTTMP/.hg/strip-backup/ea22a388757c-amend-backup.hg (glob)
236 $ hg book
236 $ hg book
237 book1 1:6cec5aa930e2
237 book1 1:6cec5aa930e2
238 * book2 1:6cec5aa930e2
238 * book2 1:6cec5aa930e2
239 $ echo a >> a
239 $ echo a >> a
240 $ hg ci --amend -m 'move bookmarks'
240 $ hg ci --amend -m 'move bookmarks'
241 saved backup bundle to $TESTTMP/.hg/strip-backup/6cec5aa930e2-amend-backup.hg (glob)
241 saved backup bundle to $TESTTMP/.hg/strip-backup/6cec5aa930e2-amend-backup.hg (glob)
242 $ hg book
242 $ hg book
243 book1 1:48bb6e53a15f
243 book1 1:48bb6e53a15f
244 * book2 1:48bb6e53a15f
244 * book2 1:48bb6e53a15f
245
245
246 abort does not loose bookmarks
246 abort does not loose bookmarks
247
247
248 $ cat > editor.sh << '__EOF__'
248 $ cat > editor.sh << '__EOF__'
249 > #!/bin/sh
249 > #!/bin/sh
250 > echo "" > "$1"
250 > echo "" > "$1"
251 > __EOF__
251 > __EOF__
252 $ echo a >> a
252 $ echo a >> a
253 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit --amend
253 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit --amend
254 transaction abort!
254 transaction abort!
255 rollback completed
255 rollback completed
256 abort: empty commit message
256 abort: empty commit message
257 [255]
257 [255]
258 $ hg book
258 $ hg book
259 book1 1:48bb6e53a15f
259 book1 1:48bb6e53a15f
260 * book2 1:48bb6e53a15f
260 * book2 1:48bb6e53a15f
261 $ hg revert -Caq
261 $ hg revert -Caq
262 $ rm editor.sh
262 $ rm editor.sh
263
263
264 $ echo '[defaults]' >> $HGRCPATH
264 $ echo '[defaults]' >> $HGRCPATH
265 $ echo "commit=-d '0 0'" >> $HGRCPATH
265 $ echo "commit=-d '0 0'" >> $HGRCPATH
266
266
267 Moving branches:
267 Moving branches:
268
268
269 $ hg branch foo
269 $ hg branch foo
270 marked working directory as branch foo
270 marked working directory as branch foo
271 (branches are permanent and global, did you want a bookmark?)
271 (branches are permanent and global, did you want a bookmark?)
272 $ echo a >> a
272 $ echo a >> a
273 $ hg ci -m 'branch foo'
273 $ hg ci -m 'branch foo'
274 $ hg branch default -f
274 $ hg branch default -f
275 marked working directory as branch default
275 marked working directory as branch default
276 (branches are permanent and global, did you want a bookmark?)
276 (branches are permanent and global, did you want a bookmark?)
277 $ hg ci --amend -m 'back to default'
277 $ hg ci --amend -m 'back to default'
278 saved backup bundle to $TESTTMP/.hg/strip-backup/8ac881fbf49d-amend-backup.hg (glob)
278 saved backup bundle to $TESTTMP/.hg/strip-backup/8ac881fbf49d-amend-backup.hg (glob)
279 $ hg branches
279 $ hg branches
280 default 2:ce12b0b57d46
280 default 2:ce12b0b57d46
281
281
282 Close branch:
282 Close branch:
283
283
284 $ hg up -q 0
284 $ hg up -q 0
285 $ echo b >> b
285 $ echo b >> b
286 $ hg branch foo
286 $ hg branch foo
287 marked working directory as branch foo
287 marked working directory as branch foo
288 (branches are permanent and global, did you want a bookmark?)
288 (branches are permanent and global, did you want a bookmark?)
289 $ hg ci -Am 'fork'
289 $ hg ci -Am 'fork'
290 adding b
290 adding b
291 $ echo b >> b
291 $ echo b >> b
292 $ hg ci -mb
292 $ hg ci -mb
293 $ hg ci --amend --close-branch -m 'closing branch foo'
293 $ hg ci --amend --close-branch -m 'closing branch foo'
294 saved backup bundle to $TESTTMP/.hg/strip-backup/c962248fa264-amend-backup.hg (glob)
294 saved backup bundle to $TESTTMP/.hg/strip-backup/c962248fa264-amend-backup.hg (glob)
295
295
296 Same thing, different code path:
296 Same thing, different code path:
297
297
298 $ echo b >> b
298 $ echo b >> b
299 $ hg ci -m 'reopen branch'
299 $ hg ci -m 'reopen branch'
300 reopening closed branch head 4
300 reopening closed branch head 4
301 $ echo b >> b
301 $ echo b >> b
302 $ hg ci --amend --close-branch
302 $ hg ci --amend --close-branch
303 saved backup bundle to $TESTTMP/.hg/strip-backup/027371728205-amend-backup.hg (glob)
303 saved backup bundle to $TESTTMP/.hg/strip-backup/027371728205-amend-backup.hg (glob)
304 $ hg branches
304 $ hg branches
305 default 2:ce12b0b57d46
305 default 2:ce12b0b57d46
306
306
307 Refuse to amend during a merge:
307 Refuse to amend during a merge:
308
308
309 $ hg up -q default
309 $ hg up -q default
310 $ hg merge foo
310 $ hg merge foo
311 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
311 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
312 (branch merge, don't forget to commit)
312 (branch merge, don't forget to commit)
313 $ hg ci --amend
313 $ hg ci --amend
314 abort: cannot amend while merging
314 abort: cannot amend while merging
315 [255]
315 [255]
316 $ hg ci -m 'merge'
316 $ hg ci -m 'merge'
317
317
318 Follow copies/renames:
318 Follow copies/renames:
319
319
320 $ hg mv b c
320 $ hg mv b c
321 $ hg ci -m 'b -> c'
321 $ hg ci -m 'b -> c'
322 $ hg mv c d
322 $ hg mv c d
323 $ hg ci --amend -m 'b -> d'
323 $ hg ci --amend -m 'b -> d'
324 saved backup bundle to $TESTTMP/.hg/strip-backup/b8c6eac7f12e-amend-backup.hg (glob)
324 saved backup bundle to $TESTTMP/.hg/strip-backup/b8c6eac7f12e-amend-backup.hg (glob)
325 $ hg st --rev '.^' --copies d
325 $ hg st --rev '.^' --copies d
326 A d
326 A d
327 b
327 b
328 $ hg cp d e
328 $ hg cp d e
329 $ hg ci -m 'e = d'
329 $ hg ci -m 'e = d'
330 $ hg cp e f
330 $ hg cp e f
331 $ hg ci --amend -m 'f = d'
331 $ hg ci --amend -m 'f = d'
332 saved backup bundle to $TESTTMP/.hg/strip-backup/7f9761d65613-amend-backup.hg (glob)
332 saved backup bundle to $TESTTMP/.hg/strip-backup/7f9761d65613-amend-backup.hg (glob)
333 $ hg st --rev '.^' --copies f
333 $ hg st --rev '.^' --copies f
334 A f
334 A f
335 d
335 d
336
336
337 $ mv f f.orig
337 $ mv f f.orig
338 $ hg rm -A f
338 $ hg rm -A f
339 $ hg ci -m removef
339 $ hg ci -m removef
340 $ hg cp a f
340 $ hg cp a f
341 $ mv f.orig f
341 $ mv f.orig f
342 $ hg ci --amend -m replacef
342 $ hg ci --amend -m replacef
343 saved backup bundle to $TESTTMP/.hg/strip-backup/9e8c5f7e3d95-amend-backup.hg (glob)
343 saved backup bundle to $TESTTMP/.hg/strip-backup/9e8c5f7e3d95-amend-backup.hg (glob)
344 $ hg st --change . --copies
344 $ hg st --change . --copies
345 $ hg log -r . --template "{file_copies}\n"
345 $ hg log -r . --template "{file_copies}\n"
346
346
347
347
348 Move added file (issue3410):
348 Move added file (issue3410):
349
349
350 $ echo g >> g
350 $ echo g >> g
351 $ hg ci -Am g
351 $ hg ci -Am g
352 adding g
352 adding g
353 $ hg mv g h
353 $ hg mv g h
354 $ hg ci --amend
354 $ hg ci --amend
355 saved backup bundle to $TESTTMP/.hg/strip-backup/24aa8eacce2b-amend-backup.hg (glob)
355 saved backup bundle to $TESTTMP/.hg/strip-backup/24aa8eacce2b-amend-backup.hg (glob)
356 $ hg st --change . --copies h
356 $ hg st --change . --copies h
357 A h
357 A h
358 $ hg log -r . --template "{file_copies}\n"
358 $ hg log -r . --template "{file_copies}\n"
359
359
360
360
361 Can't rollback an amend:
361 Can't rollback an amend:
362
362
363 $ hg rollback
363 $ hg rollback
364 no rollback information available
364 no rollback information available
365 [1]
365 [1]
366
366
367 Preserve extra dict (issue3430):
367 Preserve extra dict (issue3430):
368
368
369 $ hg branch a
369 $ hg branch a
370 marked working directory as branch a
370 marked working directory as branch a
371 (branches are permanent and global, did you want a bookmark?)
371 (branches are permanent and global, did you want a bookmark?)
372 $ echo a >> a
372 $ echo a >> a
373 $ hg ci -ma
373 $ hg ci -ma
374 $ hg ci --amend -m "a'"
374 $ hg ci --amend -m "a'"
375 saved backup bundle to $TESTTMP/.hg/strip-backup/3837aa2a2fdb-amend-backup.hg (glob)
375 saved backup bundle to $TESTTMP/.hg/strip-backup/3837aa2a2fdb-amend-backup.hg (glob)
376 $ hg log -r . --template "{branch}\n"
376 $ hg log -r . --template "{branch}\n"
377 a
377 a
378 $ hg ci --amend -m "a''"
378 $ hg ci --amend -m "a''"
379 saved backup bundle to $TESTTMP/.hg/strip-backup/c05c06be7514-amend-backup.hg (glob)
379 saved backup bundle to $TESTTMP/.hg/strip-backup/c05c06be7514-amend-backup.hg (glob)
380 $ hg log -r . --template "{branch}\n"
380 $ hg log -r . --template "{branch}\n"
381 a
381 a
382
382
383 Also preserve other entries in the dict that are in the old commit,
383 Also preserve other entries in the dict that are in the old commit,
384 first graft something so there's an additional entry:
384 first graft something so there's an additional entry:
385
385
386 $ hg up 0 -q
386 $ hg up 0 -q
387 $ echo z > z
387 $ echo z > z
388 $ hg ci -Am 'fork'
388 $ hg ci -Am 'fork'
389 adding z
389 adding z
390 created new head
390 created new head
391 $ hg up 11
391 $ hg up 11
392 5 files updated, 0 files merged, 1 files removed, 0 files unresolved
392 5 files updated, 0 files merged, 1 files removed, 0 files unresolved
393 $ hg graft 12
393 $ hg graft 12
394 grafting revision 12
394 grafting revision 12
395 $ hg ci --amend -m 'graft amend'
395 $ hg ci --amend -m 'graft amend'
396 saved backup bundle to $TESTTMP/.hg/strip-backup/bd010aea3f39-amend-backup.hg (glob)
396 saved backup bundle to $TESTTMP/.hg/strip-backup/bd010aea3f39-amend-backup.hg (glob)
397 $ hg log -r . --debug | grep extra
397 $ hg log -r . --debug | grep extra
398 extra: amend_source=bd010aea3f39f3fb2a2f884b9ccb0471cd77398e
398 extra: amend_source=bd010aea3f39f3fb2a2f884b9ccb0471cd77398e
399 extra: branch=a
399 extra: branch=a
400 extra: source=2647734878ef0236dda712fae9c1651cf694ea8a
400 extra: source=2647734878ef0236dda712fae9c1651cf694ea8a
401
401
402 Preserve phase
402 Preserve phase
403
403
404 $ hg phase '.^::.'
404 $ hg phase '.^::.'
405 11: draft
405 11: draft
406 13: draft
406 13: draft
407 $ hg phase --secret --force .
407 $ hg phase --secret --force .
408 $ hg phase '.^::.'
408 $ hg phase '.^::.'
409 11: draft
409 11: draft
410 13: secret
410 13: secret
411 $ hg commit --amend -m 'amend for phase' -q
411 $ hg commit --amend -m 'amend for phase' -q
412 $ hg phase '.^::.'
412 $ hg phase '.^::.'
413 11: draft
413 11: draft
414 13: secret
414 13: secret
415
415
416 Test amend with obsolete
416 Test amend with obsolete
417 ---------------------------
417 ---------------------------
418
418
419 Enable obsolete
419 Enable obsolete
420
420
421 $ cat > ${TESTTMP}/obs.py << EOF
421 $ cat > ${TESTTMP}/obs.py << EOF
422 > import mercurial.obsolete
422 > import mercurial.obsolete
423 > mercurial.obsolete._enabled = True
423 > mercurial.obsolete._enabled = True
424 > EOF
424 > EOF
425 $ echo '[extensions]' >> $HGRCPATH
425 $ echo '[extensions]' >> $HGRCPATH
426 $ echo "obs=${TESTTMP}/obs.py" >> $HGRCPATH
426 $ echo "obs=${TESTTMP}/obs.py" >> $HGRCPATH
427
427
428
428
429 Amend with no files changes
429 Amend with no files changes
430
430
431 $ hg id -n
431 $ hg id -n
432 13
432 13
433 $ hg ci --amend -m 'babar'
433 $ hg ci --amend -m 'babar'
434 $ hg id -n
434 $ hg id -n
435 14
435 14
436 $ hg log -Gl 3 --style=compact
436 $ hg log -Gl 3 --style=compact
437 @ 14[tip]:11 b650e6ee8614 1970-01-01 00:00 +0000 test
437 @ 14[tip]:11 b650e6ee8614 1970-01-01 00:00 +0000 test
438 | babar
438 | babar
439 |
439 |
440 | o 12:0 2647734878ef 1970-01-01 00:00 +0000 test
440 | o 12:0 2647734878ef 1970-01-01 00:00 +0000 test
441 | | fork
441 | | fork
442 | |
442 | |
443 o | 11 3334b7925910 1970-01-01 00:00 +0000 test
443 o | 11 3334b7925910 1970-01-01 00:00 +0000 test
444 | | a''
444 | | a''
445 | |
445 | |
446 $ hg log -Gl 4 --hidden --style=compact
446 $ hg log -Gl 4 --hidden --style=compact
447 @ 14[tip]:11 b650e6ee8614 1970-01-01 00:00 +0000 test
447 @ 14[tip]:11 b650e6ee8614 1970-01-01 00:00 +0000 test
448 | babar
448 | babar
449 |
449 |
450 | x 13:11 68ff8ff97044 1970-01-01 00:00 +0000 test
450 | x 13:11 68ff8ff97044 1970-01-01 00:00 +0000 test
451 |/ amend for phase
451 |/ amend for phase
452 |
452 |
453 | o 12:0 2647734878ef 1970-01-01 00:00 +0000 test
453 | o 12:0 2647734878ef 1970-01-01 00:00 +0000 test
454 | | fork
454 | | fork
455 | |
455 | |
456 o | 11 3334b7925910 1970-01-01 00:00 +0000 test
456 o | 11 3334b7925910 1970-01-01 00:00 +0000 test
457 | | a''
457 | | a''
458 | |
458 | |
459
459
460 Amend with files changes
460 Amend with files changes
461
461
462 (note: the extra commit over 15 is a temporary junk I would be happy to get
462 (note: the extra commit over 15 is a temporary junk I would be happy to get
463 ride of)
463 ride of)
464
464
465 $ echo 'babar' >> a
465 $ echo 'babar' >> a
466 $ hg commit --amend
466 $ hg commit --amend
467 $ hg log -Gl 6 --hidden --style=compact
467 $ hg log -Gl 6 --hidden --style=compact
468 @ 16[tip]:11 9f9e9bccf56c 1970-01-01 00:00 +0000 test
468 @ 16[tip]:11 9f9e9bccf56c 1970-01-01 00:00 +0000 test
469 | babar
469 | babar
470 |
470 |
471 | x 15 90fef497c56f 1970-01-01 00:00 +0000 test
471 | x 15 90fef497c56f 1970-01-01 00:00 +0000 test
472 | | temporary amend commit for b650e6ee8614
472 | | temporary amend commit for b650e6ee8614
473 | |
473 | |
474 | x 14:11 b650e6ee8614 1970-01-01 00:00 +0000 test
474 | x 14:11 b650e6ee8614 1970-01-01 00:00 +0000 test
475 |/ babar
475 |/ babar
476 |
476 |
477 | x 13:11 68ff8ff97044 1970-01-01 00:00 +0000 test
477 | x 13:11 68ff8ff97044 1970-01-01 00:00 +0000 test
478 |/ amend for phase
478 |/ amend for phase
479 |
479 |
480 | o 12:0 2647734878ef 1970-01-01 00:00 +0000 test
480 | o 12:0 2647734878ef 1970-01-01 00:00 +0000 test
481 | | fork
481 | | fork
482 | |
482 | |
483 o | 11 3334b7925910 1970-01-01 00:00 +0000 test
483 o | 11 3334b7925910 1970-01-01 00:00 +0000 test
484 | | a''
484 | | a''
485 | |
485 | |
486
486
487
487
488 Test that amend does not make it easy to create obsolescence cycle
488 Test that amend does not make it easy to create obsolescence cycle
489 ---------------------------------------------------------------------
489 ---------------------------------------------------------------------
490
490
491 $ hg id -r 14 --hidden
491 $ hg id -r 14 --hidden
492 b650e6ee8614 (a)
492 b650e6ee8614 (a)
493 $ hg revert -ar 14 --hidden
493 $ hg revert -ar 14 --hidden
494 reverting a
494 reverting a
495 $ hg commit --amend
495 $ hg commit --amend
496 $ hg id
496 $ hg id
497 b99e5df575f7 (a) tip
497 b99e5df575f7 (a) tip
498
498
499 Test that rewriting leaving instability behind is allowed
499 Test that rewriting leaving instability behind is allowed
500 ---------------------------------------------------------------------
500 ---------------------------------------------------------------------
501
501
502 $ hg up '.^'
502 $ hg up '.^'
503 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
503 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
504 $ echo 'b' >> a
504 $ echo 'b' >> a
505 $ hg log --style compact -r 'children(.)'
505 $ hg log --style compact -r 'children(.)'
506 18[tip]:11 b99e5df575f7 1970-01-01 00:00 +0000 test
506 18[tip]:11 b99e5df575f7 1970-01-01 00:00 +0000 test
507 babar
507 babar
508
508
509 $ hg commit --amend
509 $ hg commit --amend
510 $ hg log -r 'unstable()'
510 $ hg log -r 'unstable()'
511 changeset: 18:b99e5df575f7
511 changeset: 18:b99e5df575f7
512 branch: a
512 branch: a
513 parent: 11:3334b7925910
513 parent: 11:3334b7925910
514 user: test
514 user: test
515 date: Thu Jan 01 00:00:00 1970 +0000
515 date: Thu Jan 01 00:00:00 1970 +0000
516 summary: babar
516 summary: babar
517
517
518
518
519 Amend a merge changeset (with renames and conflicts from the second parent):
519 Amend a merge changeset (with renames and conflicts from the second parent):
520
520
521 $ hg up -q default
521 $ hg up -q default
522 $ hg branch -q bar
522 $ hg branch -q bar
523 $ hg cp a aa
523 $ hg cp a aa
524 $ hg mv z zz
524 $ hg mv z zz
525 $ echo cc > cc
525 $ echo cc > cc
526 $ hg add cc
526 $ hg add cc
527 $ hg ci -m aazzcc
527 $ hg ci -m aazzcc
528 $ hg up -q default
528 $ hg up -q default
529 $ echo a >> a
529 $ echo a >> a
530 $ echo dd > cc
530 $ echo dd > cc
531 $ hg add cc
531 $ hg add cc
532 $ hg ci -m aa
532 $ hg ci -m aa
533 $ hg merge -q bar
533 $ hg merge -q bar
534 warning: conflicts during merge.
534 warning: conflicts during merge.
535 merging cc incomplete! (edit conflicts, then use 'hg resolve --mark')
535 merging cc incomplete! (edit conflicts, then use 'hg resolve --mark')
536 [1]
536 [1]
537 $ hg resolve -m cc
537 $ hg resolve -m cc
538 $ hg ci -m 'merge bar'
538 $ hg ci -m 'merge bar'
539 $ hg log --config diff.git=1 -pr .
539 $ hg log --config diff.git=1 -pr .
540 changeset: 23:d51446492733
540 changeset: 23:d51446492733
541 tag: tip
541 tag: tip
542 parent: 22:30d96aeaf27b
542 parent: 22:30d96aeaf27b
543 parent: 21:1aa437659d19
543 parent: 21:1aa437659d19
544 user: test
544 user: test
545 date: Thu Jan 01 00:00:00 1970 +0000
545 date: Thu Jan 01 00:00:00 1970 +0000
546 summary: merge bar
546 summary: merge bar
547
547
548 diff --git a/a b/aa
548 diff --git a/a b/aa
549 copy from a
549 copy from a
550 copy to aa
550 copy to aa
551 diff --git a/cc b/cc
551 diff --git a/cc b/cc
552 --- a/cc
552 --- a/cc
553 +++ b/cc
553 +++ b/cc
554 @@ -1,1 +1,5 @@
554 @@ -1,1 +1,5 @@
555 +<<<<<<< local
555 +<<<<<<< local
556 dd
556 dd
557 +=======
557 +=======
558 +cc
558 +cc
559 +>>>>>>> other
559 +>>>>>>> other
560 diff --git a/z b/zz
560 diff --git a/z b/zz
561 rename from z
561 rename from z
562 rename to zz
562 rename to zz
563
563
564 $ hg debugrename aa
564 $ hg debugrename aa
565 aa renamed from a:a80d06849b333b8a3d5c445f8ba3142010dcdc9e
565 aa renamed from a:a80d06849b333b8a3d5c445f8ba3142010dcdc9e
566 $ hg debugrename zz
566 $ hg debugrename zz
567 zz renamed from z:69a1b67522704ec122181c0890bd16e9d3e7516a
567 zz renamed from z:69a1b67522704ec122181c0890bd16e9d3e7516a
568 $ hg debugrename cc
568 $ hg debugrename cc
569 cc not renamed
569 cc not renamed
570 $ hg ci --amend -m 'merge bar (amend message)'
570 $ hg ci --amend -m 'merge bar (amend message)'
571 $ hg log --config diff.git=1 -pr .
571 $ hg log --config diff.git=1 -pr .
572 changeset: 24:59de3dce7a79
572 changeset: 24:59de3dce7a79
573 tag: tip
573 tag: tip
574 parent: 22:30d96aeaf27b
574 parent: 22:30d96aeaf27b
575 parent: 21:1aa437659d19
575 parent: 21:1aa437659d19
576 user: test
576 user: test
577 date: Thu Jan 01 00:00:00 1970 +0000
577 date: Thu Jan 01 00:00:00 1970 +0000
578 summary: merge bar (amend message)
578 summary: merge bar (amend message)
579
579
580 diff --git a/a b/aa
580 diff --git a/a b/aa
581 copy from a
581 copy from a
582 copy to aa
582 copy to aa
583 diff --git a/cc b/cc
583 diff --git a/cc b/cc
584 --- a/cc
584 --- a/cc
585 +++ b/cc
585 +++ b/cc
586 @@ -1,1 +1,5 @@
586 @@ -1,1 +1,5 @@
587 +<<<<<<< local
587 +<<<<<<< local
588 dd
588 dd
589 +=======
589 +=======
590 +cc
590 +cc
591 +>>>>>>> other
591 +>>>>>>> other
592 diff --git a/z b/zz
592 diff --git a/z b/zz
593 rename from z
593 rename from z
594 rename to zz
594 rename to zz
595
595
596 $ hg debugrename aa
596 $ hg debugrename aa
597 aa renamed from a:a80d06849b333b8a3d5c445f8ba3142010dcdc9e
597 aa renamed from a:a80d06849b333b8a3d5c445f8ba3142010dcdc9e
598 $ hg debugrename zz
598 $ hg debugrename zz
599 zz renamed from z:69a1b67522704ec122181c0890bd16e9d3e7516a
599 zz renamed from z:69a1b67522704ec122181c0890bd16e9d3e7516a
600 $ hg debugrename cc
600 $ hg debugrename cc
601 cc not renamed
601 cc not renamed
602 $ hg mv zz z
602 $ hg mv zz z
603 $ hg ci --amend -m 'merge bar (undo rename)'
603 $ hg ci --amend -m 'merge bar (undo rename)'
604 $ hg log --config diff.git=1 -pr .
604 $ hg log --config diff.git=1 -pr .
605 changeset: 26:7fb89c461f81
605 changeset: 26:7fb89c461f81
606 tag: tip
606 tag: tip
607 parent: 22:30d96aeaf27b
607 parent: 22:30d96aeaf27b
608 parent: 21:1aa437659d19
608 parent: 21:1aa437659d19
609 user: test
609 user: test
610 date: Thu Jan 01 00:00:00 1970 +0000
610 date: Thu Jan 01 00:00:00 1970 +0000
611 summary: merge bar (undo rename)
611 summary: merge bar (undo rename)
612
612
613 diff --git a/a b/aa
613 diff --git a/a b/aa
614 copy from a
614 copy from a
615 copy to aa
615 copy to aa
616 diff --git a/cc b/cc
616 diff --git a/cc b/cc
617 --- a/cc
617 --- a/cc
618 +++ b/cc
618 +++ b/cc
619 @@ -1,1 +1,5 @@
619 @@ -1,1 +1,5 @@
620 +<<<<<<< local
620 +<<<<<<< local
621 dd
621 dd
622 +=======
622 +=======
623 +cc
623 +cc
624 +>>>>>>> other
624 +>>>>>>> other
625
625
626 $ hg debugrename z
626 $ hg debugrename z
627 z not renamed
627 z not renamed
628
628
629 Amend a merge changeset (with renames during the merge):
629 Amend a merge changeset (with renames during the merge):
630
630
631 $ hg up -q bar
631 $ hg up -q bar
632 $ echo x > x
632 $ echo x > x
633 $ hg add x
633 $ hg add x
634 $ hg ci -m x
634 $ hg ci -m x
635 $ hg up -q default
635 $ hg up -q default
636 $ hg merge -q bar
636 $ hg merge -q bar
637 $ hg mv aa aaa
637 $ hg mv aa aaa
638 $ echo aa >> aaa
638 $ echo aa >> aaa
639 $ hg ci -m 'merge bar again'
639 $ hg ci -m 'merge bar again'
640 $ hg log --config diff.git=1 -pr .
640 $ hg log --config diff.git=1 -pr .
641 changeset: 28:982d7a34ffee
641 changeset: 28:982d7a34ffee
642 tag: tip
642 tag: tip
643 parent: 26:7fb89c461f81
643 parent: 26:7fb89c461f81
644 parent: 27:4c94d5bc65f5
644 parent: 27:4c94d5bc65f5
645 user: test
645 user: test
646 date: Thu Jan 01 00:00:00 1970 +0000
646 date: Thu Jan 01 00:00:00 1970 +0000
647 summary: merge bar again
647 summary: merge bar again
648
648
649 diff --git a/aa b/aa
649 diff --git a/aa b/aa
650 deleted file mode 100644
650 deleted file mode 100644
651 --- a/aa
651 --- a/aa
652 +++ /dev/null
652 +++ /dev/null
653 @@ -1,2 +0,0 @@
653 @@ -1,2 +0,0 @@
654 -a
654 -a
655 -a
655 -a
656 diff --git a/aaa b/aaa
656 diff --git a/aaa b/aaa
657 new file mode 100644
657 new file mode 100644
658 --- /dev/null
658 --- /dev/null
659 +++ b/aaa
659 +++ b/aaa
660 @@ -0,0 +1,3 @@
660 @@ -0,0 +1,3 @@
661 +a
661 +a
662 +a
662 +a
663 +aa
663 +aa
664 diff --git a/x b/x
664 diff --git a/x b/x
665 new file mode 100644
665 new file mode 100644
666 --- /dev/null
666 --- /dev/null
667 +++ b/x
667 +++ b/x
668 @@ -0,0 +1,1 @@
668 @@ -0,0 +1,1 @@
669 +x
669 +x
670
670
671 $ hg debugrename aaa
671 $ hg debugrename aaa
672 aaa renamed from aa:37d9b5d994eab34eda9c16b195ace52c7b129980
672 aaa renamed from aa:37d9b5d994eab34eda9c16b195ace52c7b129980
673 $ hg mv aaa aa
673 $ hg mv aaa aa
674 $ hg ci --amend -m 'merge bar again (undo rename)'
674 $ hg ci --amend -m 'merge bar again (undo rename)'
675 $ hg log --config diff.git=1 -pr .
675 $ hg log --config diff.git=1 -pr .
676 changeset: 30:522688c0e71b
676 changeset: 30:522688c0e71b
677 tag: tip
677 tag: tip
678 parent: 26:7fb89c461f81
678 parent: 26:7fb89c461f81
679 parent: 27:4c94d5bc65f5
679 parent: 27:4c94d5bc65f5
680 user: test
680 user: test
681 date: Thu Jan 01 00:00:00 1970 +0000
681 date: Thu Jan 01 00:00:00 1970 +0000
682 summary: merge bar again (undo rename)
682 summary: merge bar again (undo rename)
683
683
684 diff --git a/aa b/aa
684 diff --git a/aa b/aa
685 --- a/aa
685 --- a/aa
686 +++ b/aa
686 +++ b/aa
687 @@ -1,2 +1,3 @@
687 @@ -1,2 +1,3 @@
688 a
688 a
689 a
689 a
690 +aa
690 +aa
691 diff --git a/x b/x
691 diff --git a/x b/x
692 new file mode 100644
692 new file mode 100644
693 --- /dev/null
693 --- /dev/null
694 +++ b/x
694 +++ b/x
695 @@ -0,0 +1,1 @@
695 @@ -0,0 +1,1 @@
696 +x
696 +x
697
697
698 $ hg debugrename aa
698 $ hg debugrename aa
699 aa not renamed
699 aa not renamed
700 $ hg debugrename -r '.^' aa
700 $ hg debugrename -r '.^' aa
701 aa renamed from a:a80d06849b333b8a3d5c445f8ba3142010dcdc9e
701 aa renamed from a:a80d06849b333b8a3d5c445f8ba3142010dcdc9e
702
702
703 Amend a merge changeset (with manifest-level conflicts):
703 Amend a merge changeset (with manifest-level conflicts):
704
704
705 $ hg up -q bar
705 $ hg up -q bar
706 $ hg rm aa
706 $ hg rm aa
707 $ hg ci -m 'rm aa'
707 $ hg ci -m 'rm aa'
708 $ hg up -q default
708 $ hg up -q default
709 $ echo aa >> aa
709 $ echo aa >> aa
710 $ hg ci -m aa
710 $ hg ci -m aa
711 $ hg merge -q bar
711 $ hg merge -q bar
712 local changed aa which remote deleted
712 local changed aa which remote deleted
713 use (c)hanged version or (d)elete? c
713 use (c)hanged version or (d)elete? c
714 $ hg ci -m 'merge bar (with conflicts)'
714 $ hg ci -m 'merge bar (with conflicts)'
715 $ hg log --config diff.git=1 -pr .
715 $ hg log --config diff.git=1 -pr .
716 changeset: 33:5f9904c491b8
716 changeset: 33:5f9904c491b8
717 tag: tip
717 tag: tip
718 parent: 32:01780b896f58
718 parent: 32:01780b896f58
719 parent: 31:67db8847a540
719 parent: 31:67db8847a540
720 user: test
720 user: test
721 date: Thu Jan 01 00:00:00 1970 +0000
721 date: Thu Jan 01 00:00:00 1970 +0000
722 summary: merge bar (with conflicts)
722 summary: merge bar (with conflicts)
723
723
724
724
725 $ hg rm aa
725 $ hg rm aa
726 $ hg ci --amend -m 'merge bar (with conflicts, amended)'
726 $ hg ci --amend -m 'merge bar (with conflicts, amended)'
727 $ hg log --config diff.git=1 -pr .
727 $ hg log --config diff.git=1 -pr .
728 changeset: 35:6ce0c89781a3
728 changeset: 35:6ce0c89781a3
729 tag: tip
729 tag: tip
730 parent: 32:01780b896f58
730 parent: 32:01780b896f58
731 parent: 31:67db8847a540
731 parent: 31:67db8847a540
732 user: test
732 user: test
733 date: Thu Jan 01 00:00:00 1970 +0000
733 date: Thu Jan 01 00:00:00 1970 +0000
734 summary: merge bar (with conflicts, amended)
734 summary: merge bar (with conflicts, amended)
735
735
736 diff --git a/aa b/aa
736 diff --git a/aa b/aa
737 deleted file mode 100644
737 deleted file mode 100644
738 --- a/aa
738 --- a/aa
739 +++ /dev/null
739 +++ /dev/null
740 @@ -1,4 +0,0 @@
740 @@ -1,4 +0,0 @@
741 -a
741 -a
742 -a
742 -a
743 -aa
743 -aa
744 -aa
744 -aa
745
745
746 Issue 3445: amending with --close-branch a commit that created a new head should fail
746 Issue 3445: amending with --close-branch a commit that created a new head should fail
747 This shouldn't be possible:
747 This shouldn't be possible:
748
748
749 $ hg up -q default
749 $ hg up -q default
750 $ hg branch closewithamend
750 $ hg branch closewithamend
751 marked working directory as branch closewithamend
751 marked working directory as branch closewithamend
752 (branches are permanent and global, did you want a bookmark?)
752 (branches are permanent and global, did you want a bookmark?)
753 $ hg add obs.py
753 $ hg add obs.py
754 $ hg ci -m..
754 $ hg ci -m..
755 $ hg ci --amend --close-branch -m 'closing'
755 $ hg ci --amend --close-branch -m 'closing'
756 abort: can only close branch heads
756 abort: can only close branch heads
757 [255]
757 [255]
758
758
759 This silliness fails:
759 This silliness fails:
760
760
761 $ hg branch silliness
761 $ hg branch silliness
762 marked working directory as branch silliness
762 marked working directory as branch silliness
763 (branches are permanent and global, did you want a bookmark?)
763 (branches are permanent and global, did you want a bookmark?)
764 $ echo b >> b
764 $ echo b >> b
765 $ hg ci --close-branch -m'open and close'
765 $ hg ci --close-branch -m'open and close'
766 abort: can only close branch heads
766 abort: can only close branch heads
767 [255]
767 [255]
768
769 Test that amend with --secret creates new secret changeset forcibly
770 ---------------------------------------------------------------------
771
772 $ hg phase '.^::.'
773 35: draft
774 36: draft
775 $ hg commit --amend --secret -m 'amend as secret' -q
776 $ hg phase '.^::.'
777 35: draft
778 38: secret
@@ -1,2124 +1,2129 b''
1 @ (34) head
1 @ (34) head
2 |
2 |
3 | o (33) head
3 | o (33) head
4 | |
4 | |
5 o | (32) expand
5 o | (32) expand
6 |\ \
6 |\ \
7 | o \ (31) expand
7 | o \ (31) expand
8 | |\ \
8 | |\ \
9 | | o \ (30) expand
9 | | o \ (30) expand
10 | | |\ \
10 | | |\ \
11 | | | o | (29) regular commit
11 | | | o | (29) regular commit
12 | | | | |
12 | | | | |
13 | | o | | (28) merge zero known
13 | | o | | (28) merge zero known
14 | | |\ \ \
14 | | |\ \ \
15 o | | | | | (27) collapse
15 o | | | | | (27) collapse
16 |/ / / / /
16 |/ / / / /
17 | | o---+ (26) merge one known; far right
17 | | o---+ (26) merge one known; far right
18 | | | | |
18 | | | | |
19 +---o | | (25) merge one known; far left
19 +---o | | (25) merge one known; far left
20 | | | | |
20 | | | | |
21 | | o | | (24) merge one known; immediate right
21 | | o | | (24) merge one known; immediate right
22 | | |\| |
22 | | |\| |
23 | | o | | (23) merge one known; immediate left
23 | | o | | (23) merge one known; immediate left
24 | |/| | |
24 | |/| | |
25 +---o---+ (22) merge two known; one far left, one far right
25 +---o---+ (22) merge two known; one far left, one far right
26 | | / /
26 | | / /
27 o | | | (21) expand
27 o | | | (21) expand
28 |\ \ \ \
28 |\ \ \ \
29 | o---+-+ (20) merge two known; two far right
29 | o---+-+ (20) merge two known; two far right
30 | / / /
30 | / / /
31 o | | | (19) expand
31 o | | | (19) expand
32 |\ \ \ \
32 |\ \ \ \
33 +---+---o (18) merge two known; two far left
33 +---+---o (18) merge two known; two far left
34 | | | |
34 | | | |
35 | o | | (17) expand
35 | o | | (17) expand
36 | |\ \ \
36 | |\ \ \
37 | | o---+ (16) merge two known; one immediate right, one near right
37 | | o---+ (16) merge two known; one immediate right, one near right
38 | | |/ /
38 | | |/ /
39 o | | | (15) expand
39 o | | | (15) expand
40 |\ \ \ \
40 |\ \ \ \
41 | o-----+ (14) merge two known; one immediate right, one far right
41 | o-----+ (14) merge two known; one immediate right, one far right
42 | |/ / /
42 | |/ / /
43 o | | | (13) expand
43 o | | | (13) expand
44 |\ \ \ \
44 |\ \ \ \
45 +---o | | (12) merge two known; one immediate right, one far left
45 +---o | | (12) merge two known; one immediate right, one far left
46 | | |/ /
46 | | |/ /
47 | o | | (11) expand
47 | o | | (11) expand
48 | |\ \ \
48 | |\ \ \
49 | | o---+ (10) merge two known; one immediate left, one near right
49 | | o---+ (10) merge two known; one immediate left, one near right
50 | |/ / /
50 | |/ / /
51 o | | | (9) expand
51 o | | | (9) expand
52 |\ \ \ \
52 |\ \ \ \
53 | o-----+ (8) merge two known; one immediate left, one far right
53 | o-----+ (8) merge two known; one immediate left, one far right
54 |/ / / /
54 |/ / / /
55 o | | | (7) expand
55 o | | | (7) expand
56 |\ \ \ \
56 |\ \ \ \
57 +---o | | (6) merge two known; one immediate left, one far left
57 +---o | | (6) merge two known; one immediate left, one far left
58 | |/ / /
58 | |/ / /
59 | o | | (5) expand
59 | o | | (5) expand
60 | |\ \ \
60 | |\ \ \
61 | | o | | (4) merge two known; one immediate left, one immediate right
61 | | o | | (4) merge two known; one immediate left, one immediate right
62 | |/|/ /
62 | |/|/ /
63 | o / / (3) collapse
63 | o / / (3) collapse
64 |/ / /
64 |/ / /
65 o / / (2) collapse
65 o / / (2) collapse
66 |/ /
66 |/ /
67 o / (1) collapse
67 o / (1) collapse
68 |/
68 |/
69 o (0) root
69 o (0) root
70
70
71
71
72 $ commit()
72 $ commit()
73 > {
73 > {
74 > rev=$1
74 > rev=$1
75 > msg=$2
75 > msg=$2
76 > shift 2
76 > shift 2
77 > if [ "$#" -gt 0 ]; then
77 > if [ "$#" -gt 0 ]; then
78 > hg debugsetparents "$@"
78 > hg debugsetparents "$@"
79 > fi
79 > fi
80 > echo $rev > a
80 > echo $rev > a
81 > hg commit -Aqd "$rev 0" -m "($rev) $msg"
81 > hg commit -Aqd "$rev 0" -m "($rev) $msg"
82 > }
82 > }
83
83
84 $ cat > printrevset.py <<EOF
84 $ cat > printrevset.py <<EOF
85 > from mercurial import extensions, revset, commands, cmdutil
85 > from mercurial import extensions, revset, commands, cmdutil
86 >
86 >
87 > def uisetup(ui):
87 > def uisetup(ui):
88 > def printrevset(orig, ui, repo, *pats, **opts):
88 > def printrevset(orig, ui, repo, *pats, **opts):
89 > if opts.get('print_revset'):
89 > if opts.get('print_revset'):
90 > expr = cmdutil.getgraphlogrevs(repo, pats, opts)[1]
90 > expr = cmdutil.getgraphlogrevs(repo, pats, opts)[1]
91 > if expr:
91 > if expr:
92 > tree = revset.parse(expr)[0]
92 > tree = revset.parse(expr)[0]
93 > else:
93 > else:
94 > tree = []
94 > tree = []
95 > ui.write('%r\n' % (opts.get('rev', []),))
95 > ui.write('%r\n' % (opts.get('rev', []),))
96 > ui.write(revset.prettyformat(tree) + '\n')
96 > ui.write(revset.prettyformat(tree) + '\n')
97 > return 0
97 > return 0
98 > return orig(ui, repo, *pats, **opts)
98 > return orig(ui, repo, *pats, **opts)
99 > entry = extensions.wrapcommand(commands.table, 'log', printrevset)
99 > entry = extensions.wrapcommand(commands.table, 'log', printrevset)
100 > entry[1].append(('', 'print-revset', False,
100 > entry[1].append(('', 'print-revset', False,
101 > 'print generated revset and exit (DEPRECATED)'))
101 > 'print generated revset and exit (DEPRECATED)'))
102 > EOF
102 > EOF
103
103
104 $ echo "[extensions]" >> $HGRCPATH
104 $ echo "[extensions]" >> $HGRCPATH
105 $ echo "printrevset=`pwd`/printrevset.py" >> $HGRCPATH
105 $ echo "printrevset=`pwd`/printrevset.py" >> $HGRCPATH
106
106
107 $ hg init repo
107 $ hg init repo
108 $ cd repo
108 $ cd repo
109
109
110 Empty repo:
110 Empty repo:
111
111
112 $ hg log -G
112 $ hg log -G
113
113
114
114
115 Building DAG:
115 Building DAG:
116
116
117 $ commit 0 "root"
117 $ commit 0 "root"
118 $ commit 1 "collapse" 0
118 $ commit 1 "collapse" 0
119 $ commit 2 "collapse" 1
119 $ commit 2 "collapse" 1
120 $ commit 3 "collapse" 2
120 $ commit 3 "collapse" 2
121 $ commit 4 "merge two known; one immediate left, one immediate right" 1 3
121 $ commit 4 "merge two known; one immediate left, one immediate right" 1 3
122 $ commit 5 "expand" 3 4
122 $ commit 5 "expand" 3 4
123 $ commit 6 "merge two known; one immediate left, one far left" 2 5
123 $ commit 6 "merge two known; one immediate left, one far left" 2 5
124 $ commit 7 "expand" 2 5
124 $ commit 7 "expand" 2 5
125 $ commit 8 "merge two known; one immediate left, one far right" 0 7
125 $ commit 8 "merge two known; one immediate left, one far right" 0 7
126 $ commit 9 "expand" 7 8
126 $ commit 9 "expand" 7 8
127 $ commit 10 "merge two known; one immediate left, one near right" 0 6
127 $ commit 10 "merge two known; one immediate left, one near right" 0 6
128 $ commit 11 "expand" 6 10
128 $ commit 11 "expand" 6 10
129 $ commit 12 "merge two known; one immediate right, one far left" 1 9
129 $ commit 12 "merge two known; one immediate right, one far left" 1 9
130 $ commit 13 "expand" 9 11
130 $ commit 13 "expand" 9 11
131 $ commit 14 "merge two known; one immediate right, one far right" 0 12
131 $ commit 14 "merge two known; one immediate right, one far right" 0 12
132 $ commit 15 "expand" 13 14
132 $ commit 15 "expand" 13 14
133 $ commit 16 "merge two known; one immediate right, one near right" 0 1
133 $ commit 16 "merge two known; one immediate right, one near right" 0 1
134 $ commit 17 "expand" 12 16
134 $ commit 17 "expand" 12 16
135 $ commit 18 "merge two known; two far left" 1 15
135 $ commit 18 "merge two known; two far left" 1 15
136 $ commit 19 "expand" 15 17
136 $ commit 19 "expand" 15 17
137 $ commit 20 "merge two known; two far right" 0 18
137 $ commit 20 "merge two known; two far right" 0 18
138 $ commit 21 "expand" 19 20
138 $ commit 21 "expand" 19 20
139 $ commit 22 "merge two known; one far left, one far right" 18 21
139 $ commit 22 "merge two known; one far left, one far right" 18 21
140 $ commit 23 "merge one known; immediate left" 1 22
140 $ commit 23 "merge one known; immediate left" 1 22
141 $ commit 24 "merge one known; immediate right" 0 23
141 $ commit 24 "merge one known; immediate right" 0 23
142 $ commit 25 "merge one known; far left" 21 24
142 $ commit 25 "merge one known; far left" 21 24
143 $ commit 26 "merge one known; far right" 18 25
143 $ commit 26 "merge one known; far right" 18 25
144 $ commit 27 "collapse" 21
144 $ commit 27 "collapse" 21
145 $ commit 28 "merge zero known" 1 26
145 $ commit 28 "merge zero known" 1 26
146 $ commit 29 "regular commit" 0
146 $ commit 29 "regular commit" 0
147 $ commit 30 "expand" 28 29
147 $ commit 30 "expand" 28 29
148 $ commit 31 "expand" 21 30
148 $ commit 31 "expand" 21 30
149 $ commit 32 "expand" 27 31
149 $ commit 32 "expand" 27 31
150 $ commit 33 "head" 18
150 $ commit 33 "head" 18
151 $ commit 34 "head" 32
151 $ commit 34 "head" 32
152
152
153
153
154 $ hg log -G -q
154 $ hg log -G -q
155 @ 34:fea3ac5810e0
155 @ 34:fea3ac5810e0
156 |
156 |
157 | o 33:68608f5145f9
157 | o 33:68608f5145f9
158 | |
158 | |
159 o | 32:d06dffa21a31
159 o | 32:d06dffa21a31
160 |\ \
160 |\ \
161 | o \ 31:621d83e11f67
161 | o \ 31:621d83e11f67
162 | |\ \
162 | |\ \
163 | | o \ 30:6e11cd4b648f
163 | | o \ 30:6e11cd4b648f
164 | | |\ \
164 | | |\ \
165 | | | o | 29:cd9bb2be7593
165 | | | o | 29:cd9bb2be7593
166 | | | | |
166 | | | | |
167 | | o | | 28:44ecd0b9ae99
167 | | o | | 28:44ecd0b9ae99
168 | | |\ \ \
168 | | |\ \ \
169 o | | | | | 27:886ed638191b
169 o | | | | | 27:886ed638191b
170 |/ / / / /
170 |/ / / / /
171 | | o---+ 26:7f25b6c2f0b9
171 | | o---+ 26:7f25b6c2f0b9
172 | | | | |
172 | | | | |
173 +---o | | 25:91da8ed57247
173 +---o | | 25:91da8ed57247
174 | | | | |
174 | | | | |
175 | | o | | 24:a9c19a3d96b7
175 | | o | | 24:a9c19a3d96b7
176 | | |\| |
176 | | |\| |
177 | | o | | 23:a01cddf0766d
177 | | o | | 23:a01cddf0766d
178 | |/| | |
178 | |/| | |
179 +---o---+ 22:e0d9cccacb5d
179 +---o---+ 22:e0d9cccacb5d
180 | | / /
180 | | / /
181 o | | | 21:d42a756af44d
181 o | | | 21:d42a756af44d
182 |\ \ \ \
182 |\ \ \ \
183 | o---+-+ 20:d30ed6450e32
183 | o---+-+ 20:d30ed6450e32
184 | / / /
184 | / / /
185 o | | | 19:31ddc2c1573b
185 o | | | 19:31ddc2c1573b
186 |\ \ \ \
186 |\ \ \ \
187 +---+---o 18:1aa84d96232a
187 +---+---o 18:1aa84d96232a
188 | | | |
188 | | | |
189 | o | | 17:44765d7c06e0
189 | o | | 17:44765d7c06e0
190 | |\ \ \
190 | |\ \ \
191 | | o---+ 16:3677d192927d
191 | | o---+ 16:3677d192927d
192 | | |/ /
192 | | |/ /
193 o | | | 15:1dda3f72782d
193 o | | | 15:1dda3f72782d
194 |\ \ \ \
194 |\ \ \ \
195 | o-----+ 14:8eac370358ef
195 | o-----+ 14:8eac370358ef
196 | |/ / /
196 | |/ / /
197 o | | | 13:22d8966a97e3
197 o | | | 13:22d8966a97e3
198 |\ \ \ \
198 |\ \ \ \
199 +---o | | 12:86b91144a6e9
199 +---o | | 12:86b91144a6e9
200 | | |/ /
200 | | |/ /
201 | o | | 11:832d76e6bdf2
201 | o | | 11:832d76e6bdf2
202 | |\ \ \
202 | |\ \ \
203 | | o---+ 10:74c64d036d72
203 | | o---+ 10:74c64d036d72
204 | |/ / /
204 | |/ / /
205 o | | | 9:7010c0af0a35
205 o | | | 9:7010c0af0a35
206 |\ \ \ \
206 |\ \ \ \
207 | o-----+ 8:7a0b11f71937
207 | o-----+ 8:7a0b11f71937
208 |/ / / /
208 |/ / / /
209 o | | | 7:b632bb1b1224
209 o | | | 7:b632bb1b1224
210 |\ \ \ \
210 |\ \ \ \
211 +---o | | 6:b105a072e251
211 +---o | | 6:b105a072e251
212 | |/ / /
212 | |/ / /
213 | o | | 5:4409d547b708
213 | o | | 5:4409d547b708
214 | |\ \ \
214 | |\ \ \
215 | | o | | 4:26a8bac39d9f
215 | | o | | 4:26a8bac39d9f
216 | |/|/ /
216 | |/|/ /
217 | o / / 3:27eef8ed80b4
217 | o / / 3:27eef8ed80b4
218 |/ / /
218 |/ / /
219 o / / 2:3d9a33b8d1e1
219 o / / 2:3d9a33b8d1e1
220 |/ /
220 |/ /
221 o / 1:6db2ef61d156
221 o / 1:6db2ef61d156
222 |/
222 |/
223 o 0:e6eb3150255d
223 o 0:e6eb3150255d
224
224
225
225
226 $ hg log -G
226 $ hg log -G
227 @ changeset: 34:fea3ac5810e0
227 @ changeset: 34:fea3ac5810e0
228 | tag: tip
228 | tag: tip
229 | parent: 32:d06dffa21a31
229 | parent: 32:d06dffa21a31
230 | user: test
230 | user: test
231 | date: Thu Jan 01 00:00:34 1970 +0000
231 | date: Thu Jan 01 00:00:34 1970 +0000
232 | summary: (34) head
232 | summary: (34) head
233 |
233 |
234 | o changeset: 33:68608f5145f9
234 | o changeset: 33:68608f5145f9
235 | | parent: 18:1aa84d96232a
235 | | parent: 18:1aa84d96232a
236 | | user: test
236 | | user: test
237 | | date: Thu Jan 01 00:00:33 1970 +0000
237 | | date: Thu Jan 01 00:00:33 1970 +0000
238 | | summary: (33) head
238 | | summary: (33) head
239 | |
239 | |
240 o | changeset: 32:d06dffa21a31
240 o | changeset: 32:d06dffa21a31
241 |\ \ parent: 27:886ed638191b
241 |\ \ parent: 27:886ed638191b
242 | | | parent: 31:621d83e11f67
242 | | | parent: 31:621d83e11f67
243 | | | user: test
243 | | | user: test
244 | | | date: Thu Jan 01 00:00:32 1970 +0000
244 | | | date: Thu Jan 01 00:00:32 1970 +0000
245 | | | summary: (32) expand
245 | | | summary: (32) expand
246 | | |
246 | | |
247 | o | changeset: 31:621d83e11f67
247 | o | changeset: 31:621d83e11f67
248 | |\ \ parent: 21:d42a756af44d
248 | |\ \ parent: 21:d42a756af44d
249 | | | | parent: 30:6e11cd4b648f
249 | | | | parent: 30:6e11cd4b648f
250 | | | | user: test
250 | | | | user: test
251 | | | | date: Thu Jan 01 00:00:31 1970 +0000
251 | | | | date: Thu Jan 01 00:00:31 1970 +0000
252 | | | | summary: (31) expand
252 | | | | summary: (31) expand
253 | | | |
253 | | | |
254 | | o | changeset: 30:6e11cd4b648f
254 | | o | changeset: 30:6e11cd4b648f
255 | | |\ \ parent: 28:44ecd0b9ae99
255 | | |\ \ parent: 28:44ecd0b9ae99
256 | | | | | parent: 29:cd9bb2be7593
256 | | | | | parent: 29:cd9bb2be7593
257 | | | | | user: test
257 | | | | | user: test
258 | | | | | date: Thu Jan 01 00:00:30 1970 +0000
258 | | | | | date: Thu Jan 01 00:00:30 1970 +0000
259 | | | | | summary: (30) expand
259 | | | | | summary: (30) expand
260 | | | | |
260 | | | | |
261 | | | o | changeset: 29:cd9bb2be7593
261 | | | o | changeset: 29:cd9bb2be7593
262 | | | | | parent: 0:e6eb3150255d
262 | | | | | parent: 0:e6eb3150255d
263 | | | | | user: test
263 | | | | | user: test
264 | | | | | date: Thu Jan 01 00:00:29 1970 +0000
264 | | | | | date: Thu Jan 01 00:00:29 1970 +0000
265 | | | | | summary: (29) regular commit
265 | | | | | summary: (29) regular commit
266 | | | | |
266 | | | | |
267 | | o | | changeset: 28:44ecd0b9ae99
267 | | o | | changeset: 28:44ecd0b9ae99
268 | | |\ \ \ parent: 1:6db2ef61d156
268 | | |\ \ \ parent: 1:6db2ef61d156
269 | | | | | | parent: 26:7f25b6c2f0b9
269 | | | | | | parent: 26:7f25b6c2f0b9
270 | | | | | | user: test
270 | | | | | | user: test
271 | | | | | | date: Thu Jan 01 00:00:28 1970 +0000
271 | | | | | | date: Thu Jan 01 00:00:28 1970 +0000
272 | | | | | | summary: (28) merge zero known
272 | | | | | | summary: (28) merge zero known
273 | | | | | |
273 | | | | | |
274 o | | | | | changeset: 27:886ed638191b
274 o | | | | | changeset: 27:886ed638191b
275 |/ / / / / parent: 21:d42a756af44d
275 |/ / / / / parent: 21:d42a756af44d
276 | | | | | user: test
276 | | | | | user: test
277 | | | | | date: Thu Jan 01 00:00:27 1970 +0000
277 | | | | | date: Thu Jan 01 00:00:27 1970 +0000
278 | | | | | summary: (27) collapse
278 | | | | | summary: (27) collapse
279 | | | | |
279 | | | | |
280 | | o---+ changeset: 26:7f25b6c2f0b9
280 | | o---+ changeset: 26:7f25b6c2f0b9
281 | | | | | parent: 18:1aa84d96232a
281 | | | | | parent: 18:1aa84d96232a
282 | | | | | parent: 25:91da8ed57247
282 | | | | | parent: 25:91da8ed57247
283 | | | | | user: test
283 | | | | | user: test
284 | | | | | date: Thu Jan 01 00:00:26 1970 +0000
284 | | | | | date: Thu Jan 01 00:00:26 1970 +0000
285 | | | | | summary: (26) merge one known; far right
285 | | | | | summary: (26) merge one known; far right
286 | | | | |
286 | | | | |
287 +---o | | changeset: 25:91da8ed57247
287 +---o | | changeset: 25:91da8ed57247
288 | | | | | parent: 21:d42a756af44d
288 | | | | | parent: 21:d42a756af44d
289 | | | | | parent: 24:a9c19a3d96b7
289 | | | | | parent: 24:a9c19a3d96b7
290 | | | | | user: test
290 | | | | | user: test
291 | | | | | date: Thu Jan 01 00:00:25 1970 +0000
291 | | | | | date: Thu Jan 01 00:00:25 1970 +0000
292 | | | | | summary: (25) merge one known; far left
292 | | | | | summary: (25) merge one known; far left
293 | | | | |
293 | | | | |
294 | | o | | changeset: 24:a9c19a3d96b7
294 | | o | | changeset: 24:a9c19a3d96b7
295 | | |\| | parent: 0:e6eb3150255d
295 | | |\| | parent: 0:e6eb3150255d
296 | | | | | parent: 23:a01cddf0766d
296 | | | | | parent: 23:a01cddf0766d
297 | | | | | user: test
297 | | | | | user: test
298 | | | | | date: Thu Jan 01 00:00:24 1970 +0000
298 | | | | | date: Thu Jan 01 00:00:24 1970 +0000
299 | | | | | summary: (24) merge one known; immediate right
299 | | | | | summary: (24) merge one known; immediate right
300 | | | | |
300 | | | | |
301 | | o | | changeset: 23:a01cddf0766d
301 | | o | | changeset: 23:a01cddf0766d
302 | |/| | | parent: 1:6db2ef61d156
302 | |/| | | parent: 1:6db2ef61d156
303 | | | | | parent: 22:e0d9cccacb5d
303 | | | | | parent: 22:e0d9cccacb5d
304 | | | | | user: test
304 | | | | | user: test
305 | | | | | date: Thu Jan 01 00:00:23 1970 +0000
305 | | | | | date: Thu Jan 01 00:00:23 1970 +0000
306 | | | | | summary: (23) merge one known; immediate left
306 | | | | | summary: (23) merge one known; immediate left
307 | | | | |
307 | | | | |
308 +---o---+ changeset: 22:e0d9cccacb5d
308 +---o---+ changeset: 22:e0d9cccacb5d
309 | | | | parent: 18:1aa84d96232a
309 | | | | parent: 18:1aa84d96232a
310 | | / / parent: 21:d42a756af44d
310 | | / / parent: 21:d42a756af44d
311 | | | | user: test
311 | | | | user: test
312 | | | | date: Thu Jan 01 00:00:22 1970 +0000
312 | | | | date: Thu Jan 01 00:00:22 1970 +0000
313 | | | | summary: (22) merge two known; one far left, one far right
313 | | | | summary: (22) merge two known; one far left, one far right
314 | | | |
314 | | | |
315 o | | | changeset: 21:d42a756af44d
315 o | | | changeset: 21:d42a756af44d
316 |\ \ \ \ parent: 19:31ddc2c1573b
316 |\ \ \ \ parent: 19:31ddc2c1573b
317 | | | | | parent: 20:d30ed6450e32
317 | | | | | parent: 20:d30ed6450e32
318 | | | | | user: test
318 | | | | | user: test
319 | | | | | date: Thu Jan 01 00:00:21 1970 +0000
319 | | | | | date: Thu Jan 01 00:00:21 1970 +0000
320 | | | | | summary: (21) expand
320 | | | | | summary: (21) expand
321 | | | | |
321 | | | | |
322 | o---+-+ changeset: 20:d30ed6450e32
322 | o---+-+ changeset: 20:d30ed6450e32
323 | | | | parent: 0:e6eb3150255d
323 | | | | parent: 0:e6eb3150255d
324 | / / / parent: 18:1aa84d96232a
324 | / / / parent: 18:1aa84d96232a
325 | | | | user: test
325 | | | | user: test
326 | | | | date: Thu Jan 01 00:00:20 1970 +0000
326 | | | | date: Thu Jan 01 00:00:20 1970 +0000
327 | | | | summary: (20) merge two known; two far right
327 | | | | summary: (20) merge two known; two far right
328 | | | |
328 | | | |
329 o | | | changeset: 19:31ddc2c1573b
329 o | | | changeset: 19:31ddc2c1573b
330 |\ \ \ \ parent: 15:1dda3f72782d
330 |\ \ \ \ parent: 15:1dda3f72782d
331 | | | | | parent: 17:44765d7c06e0
331 | | | | | parent: 17:44765d7c06e0
332 | | | | | user: test
332 | | | | | user: test
333 | | | | | date: Thu Jan 01 00:00:19 1970 +0000
333 | | | | | date: Thu Jan 01 00:00:19 1970 +0000
334 | | | | | summary: (19) expand
334 | | | | | summary: (19) expand
335 | | | | |
335 | | | | |
336 +---+---o changeset: 18:1aa84d96232a
336 +---+---o changeset: 18:1aa84d96232a
337 | | | | parent: 1:6db2ef61d156
337 | | | | parent: 1:6db2ef61d156
338 | | | | parent: 15:1dda3f72782d
338 | | | | parent: 15:1dda3f72782d
339 | | | | user: test
339 | | | | user: test
340 | | | | date: Thu Jan 01 00:00:18 1970 +0000
340 | | | | date: Thu Jan 01 00:00:18 1970 +0000
341 | | | | summary: (18) merge two known; two far left
341 | | | | summary: (18) merge two known; two far left
342 | | | |
342 | | | |
343 | o | | changeset: 17:44765d7c06e0
343 | o | | changeset: 17:44765d7c06e0
344 | |\ \ \ parent: 12:86b91144a6e9
344 | |\ \ \ parent: 12:86b91144a6e9
345 | | | | | parent: 16:3677d192927d
345 | | | | | parent: 16:3677d192927d
346 | | | | | user: test
346 | | | | | user: test
347 | | | | | date: Thu Jan 01 00:00:17 1970 +0000
347 | | | | | date: Thu Jan 01 00:00:17 1970 +0000
348 | | | | | summary: (17) expand
348 | | | | | summary: (17) expand
349 | | | | |
349 | | | | |
350 | | o---+ changeset: 16:3677d192927d
350 | | o---+ changeset: 16:3677d192927d
351 | | | | | parent: 0:e6eb3150255d
351 | | | | | parent: 0:e6eb3150255d
352 | | |/ / parent: 1:6db2ef61d156
352 | | |/ / parent: 1:6db2ef61d156
353 | | | | user: test
353 | | | | user: test
354 | | | | date: Thu Jan 01 00:00:16 1970 +0000
354 | | | | date: Thu Jan 01 00:00:16 1970 +0000
355 | | | | summary: (16) merge two known; one immediate right, one near right
355 | | | | summary: (16) merge two known; one immediate right, one near right
356 | | | |
356 | | | |
357 o | | | changeset: 15:1dda3f72782d
357 o | | | changeset: 15:1dda3f72782d
358 |\ \ \ \ parent: 13:22d8966a97e3
358 |\ \ \ \ parent: 13:22d8966a97e3
359 | | | | | parent: 14:8eac370358ef
359 | | | | | parent: 14:8eac370358ef
360 | | | | | user: test
360 | | | | | user: test
361 | | | | | date: Thu Jan 01 00:00:15 1970 +0000
361 | | | | | date: Thu Jan 01 00:00:15 1970 +0000
362 | | | | | summary: (15) expand
362 | | | | | summary: (15) expand
363 | | | | |
363 | | | | |
364 | o-----+ changeset: 14:8eac370358ef
364 | o-----+ changeset: 14:8eac370358ef
365 | | | | | parent: 0:e6eb3150255d
365 | | | | | parent: 0:e6eb3150255d
366 | |/ / / parent: 12:86b91144a6e9
366 | |/ / / parent: 12:86b91144a6e9
367 | | | | user: test
367 | | | | user: test
368 | | | | date: Thu Jan 01 00:00:14 1970 +0000
368 | | | | date: Thu Jan 01 00:00:14 1970 +0000
369 | | | | summary: (14) merge two known; one immediate right, one far right
369 | | | | summary: (14) merge two known; one immediate right, one far right
370 | | | |
370 | | | |
371 o | | | changeset: 13:22d8966a97e3
371 o | | | changeset: 13:22d8966a97e3
372 |\ \ \ \ parent: 9:7010c0af0a35
372 |\ \ \ \ parent: 9:7010c0af0a35
373 | | | | | parent: 11:832d76e6bdf2
373 | | | | | parent: 11:832d76e6bdf2
374 | | | | | user: test
374 | | | | | user: test
375 | | | | | date: Thu Jan 01 00:00:13 1970 +0000
375 | | | | | date: Thu Jan 01 00:00:13 1970 +0000
376 | | | | | summary: (13) expand
376 | | | | | summary: (13) expand
377 | | | | |
377 | | | | |
378 +---o | | changeset: 12:86b91144a6e9
378 +---o | | changeset: 12:86b91144a6e9
379 | | |/ / parent: 1:6db2ef61d156
379 | | |/ / parent: 1:6db2ef61d156
380 | | | | parent: 9:7010c0af0a35
380 | | | | parent: 9:7010c0af0a35
381 | | | | user: test
381 | | | | user: test
382 | | | | date: Thu Jan 01 00:00:12 1970 +0000
382 | | | | date: Thu Jan 01 00:00:12 1970 +0000
383 | | | | summary: (12) merge two known; one immediate right, one far left
383 | | | | summary: (12) merge two known; one immediate right, one far left
384 | | | |
384 | | | |
385 | o | | changeset: 11:832d76e6bdf2
385 | o | | changeset: 11:832d76e6bdf2
386 | |\ \ \ parent: 6:b105a072e251
386 | |\ \ \ parent: 6:b105a072e251
387 | | | | | parent: 10:74c64d036d72
387 | | | | | parent: 10:74c64d036d72
388 | | | | | user: test
388 | | | | | user: test
389 | | | | | date: Thu Jan 01 00:00:11 1970 +0000
389 | | | | | date: Thu Jan 01 00:00:11 1970 +0000
390 | | | | | summary: (11) expand
390 | | | | | summary: (11) expand
391 | | | | |
391 | | | | |
392 | | o---+ changeset: 10:74c64d036d72
392 | | o---+ changeset: 10:74c64d036d72
393 | | | | | parent: 0:e6eb3150255d
393 | | | | | parent: 0:e6eb3150255d
394 | |/ / / parent: 6:b105a072e251
394 | |/ / / parent: 6:b105a072e251
395 | | | | user: test
395 | | | | user: test
396 | | | | date: Thu Jan 01 00:00:10 1970 +0000
396 | | | | date: Thu Jan 01 00:00:10 1970 +0000
397 | | | | summary: (10) merge two known; one immediate left, one near right
397 | | | | summary: (10) merge two known; one immediate left, one near right
398 | | | |
398 | | | |
399 o | | | changeset: 9:7010c0af0a35
399 o | | | changeset: 9:7010c0af0a35
400 |\ \ \ \ parent: 7:b632bb1b1224
400 |\ \ \ \ parent: 7:b632bb1b1224
401 | | | | | parent: 8:7a0b11f71937
401 | | | | | parent: 8:7a0b11f71937
402 | | | | | user: test
402 | | | | | user: test
403 | | | | | date: Thu Jan 01 00:00:09 1970 +0000
403 | | | | | date: Thu Jan 01 00:00:09 1970 +0000
404 | | | | | summary: (9) expand
404 | | | | | summary: (9) expand
405 | | | | |
405 | | | | |
406 | o-----+ changeset: 8:7a0b11f71937
406 | o-----+ changeset: 8:7a0b11f71937
407 | | | | | parent: 0:e6eb3150255d
407 | | | | | parent: 0:e6eb3150255d
408 |/ / / / parent: 7:b632bb1b1224
408 |/ / / / parent: 7:b632bb1b1224
409 | | | | user: test
409 | | | | user: test
410 | | | | date: Thu Jan 01 00:00:08 1970 +0000
410 | | | | date: Thu Jan 01 00:00:08 1970 +0000
411 | | | | summary: (8) merge two known; one immediate left, one far right
411 | | | | summary: (8) merge two known; one immediate left, one far right
412 | | | |
412 | | | |
413 o | | | changeset: 7:b632bb1b1224
413 o | | | changeset: 7:b632bb1b1224
414 |\ \ \ \ parent: 2:3d9a33b8d1e1
414 |\ \ \ \ parent: 2:3d9a33b8d1e1
415 | | | | | parent: 5:4409d547b708
415 | | | | | parent: 5:4409d547b708
416 | | | | | user: test
416 | | | | | user: test
417 | | | | | date: Thu Jan 01 00:00:07 1970 +0000
417 | | | | | date: Thu Jan 01 00:00:07 1970 +0000
418 | | | | | summary: (7) expand
418 | | | | | summary: (7) expand
419 | | | | |
419 | | | | |
420 +---o | | changeset: 6:b105a072e251
420 +---o | | changeset: 6:b105a072e251
421 | |/ / / parent: 2:3d9a33b8d1e1
421 | |/ / / parent: 2:3d9a33b8d1e1
422 | | | | parent: 5:4409d547b708
422 | | | | parent: 5:4409d547b708
423 | | | | user: test
423 | | | | user: test
424 | | | | date: Thu Jan 01 00:00:06 1970 +0000
424 | | | | date: Thu Jan 01 00:00:06 1970 +0000
425 | | | | summary: (6) merge two known; one immediate left, one far left
425 | | | | summary: (6) merge two known; one immediate left, one far left
426 | | | |
426 | | | |
427 | o | | changeset: 5:4409d547b708
427 | o | | changeset: 5:4409d547b708
428 | |\ \ \ parent: 3:27eef8ed80b4
428 | |\ \ \ parent: 3:27eef8ed80b4
429 | | | | | parent: 4:26a8bac39d9f
429 | | | | | parent: 4:26a8bac39d9f
430 | | | | | user: test
430 | | | | | user: test
431 | | | | | date: Thu Jan 01 00:00:05 1970 +0000
431 | | | | | date: Thu Jan 01 00:00:05 1970 +0000
432 | | | | | summary: (5) expand
432 | | | | | summary: (5) expand
433 | | | | |
433 | | | | |
434 | | o | | changeset: 4:26a8bac39d9f
434 | | o | | changeset: 4:26a8bac39d9f
435 | |/|/ / parent: 1:6db2ef61d156
435 | |/|/ / parent: 1:6db2ef61d156
436 | | | | parent: 3:27eef8ed80b4
436 | | | | parent: 3:27eef8ed80b4
437 | | | | user: test
437 | | | | user: test
438 | | | | date: Thu Jan 01 00:00:04 1970 +0000
438 | | | | date: Thu Jan 01 00:00:04 1970 +0000
439 | | | | summary: (4) merge two known; one immediate left, one immediate right
439 | | | | summary: (4) merge two known; one immediate left, one immediate right
440 | | | |
440 | | | |
441 | o | | changeset: 3:27eef8ed80b4
441 | o | | changeset: 3:27eef8ed80b4
442 |/ / / user: test
442 |/ / / user: test
443 | | | date: Thu Jan 01 00:00:03 1970 +0000
443 | | | date: Thu Jan 01 00:00:03 1970 +0000
444 | | | summary: (3) collapse
444 | | | summary: (3) collapse
445 | | |
445 | | |
446 o | | changeset: 2:3d9a33b8d1e1
446 o | | changeset: 2:3d9a33b8d1e1
447 |/ / user: test
447 |/ / user: test
448 | | date: Thu Jan 01 00:00:02 1970 +0000
448 | | date: Thu Jan 01 00:00:02 1970 +0000
449 | | summary: (2) collapse
449 | | summary: (2) collapse
450 | |
450 | |
451 o | changeset: 1:6db2ef61d156
451 o | changeset: 1:6db2ef61d156
452 |/ user: test
452 |/ user: test
453 | date: Thu Jan 01 00:00:01 1970 +0000
453 | date: Thu Jan 01 00:00:01 1970 +0000
454 | summary: (1) collapse
454 | summary: (1) collapse
455 |
455 |
456 o changeset: 0:e6eb3150255d
456 o changeset: 0:e6eb3150255d
457 user: test
457 user: test
458 date: Thu Jan 01 00:00:00 1970 +0000
458 date: Thu Jan 01 00:00:00 1970 +0000
459 summary: (0) root
459 summary: (0) root
460
460
461
461
462 File glog:
462 File glog:
463 $ hg log -G a
463 $ hg log -G a
464 @ changeset: 34:fea3ac5810e0
464 @ changeset: 34:fea3ac5810e0
465 | tag: tip
465 | tag: tip
466 | parent: 32:d06dffa21a31
466 | parent: 32:d06dffa21a31
467 | user: test
467 | user: test
468 | date: Thu Jan 01 00:00:34 1970 +0000
468 | date: Thu Jan 01 00:00:34 1970 +0000
469 | summary: (34) head
469 | summary: (34) head
470 |
470 |
471 | o changeset: 33:68608f5145f9
471 | o changeset: 33:68608f5145f9
472 | | parent: 18:1aa84d96232a
472 | | parent: 18:1aa84d96232a
473 | | user: test
473 | | user: test
474 | | date: Thu Jan 01 00:00:33 1970 +0000
474 | | date: Thu Jan 01 00:00:33 1970 +0000
475 | | summary: (33) head
475 | | summary: (33) head
476 | |
476 | |
477 o | changeset: 32:d06dffa21a31
477 o | changeset: 32:d06dffa21a31
478 |\ \ parent: 27:886ed638191b
478 |\ \ parent: 27:886ed638191b
479 | | | parent: 31:621d83e11f67
479 | | | parent: 31:621d83e11f67
480 | | | user: test
480 | | | user: test
481 | | | date: Thu Jan 01 00:00:32 1970 +0000
481 | | | date: Thu Jan 01 00:00:32 1970 +0000
482 | | | summary: (32) expand
482 | | | summary: (32) expand
483 | | |
483 | | |
484 | o | changeset: 31:621d83e11f67
484 | o | changeset: 31:621d83e11f67
485 | |\ \ parent: 21:d42a756af44d
485 | |\ \ parent: 21:d42a756af44d
486 | | | | parent: 30:6e11cd4b648f
486 | | | | parent: 30:6e11cd4b648f
487 | | | | user: test
487 | | | | user: test
488 | | | | date: Thu Jan 01 00:00:31 1970 +0000
488 | | | | date: Thu Jan 01 00:00:31 1970 +0000
489 | | | | summary: (31) expand
489 | | | | summary: (31) expand
490 | | | |
490 | | | |
491 | | o | changeset: 30:6e11cd4b648f
491 | | o | changeset: 30:6e11cd4b648f
492 | | |\ \ parent: 28:44ecd0b9ae99
492 | | |\ \ parent: 28:44ecd0b9ae99
493 | | | | | parent: 29:cd9bb2be7593
493 | | | | | parent: 29:cd9bb2be7593
494 | | | | | user: test
494 | | | | | user: test
495 | | | | | date: Thu Jan 01 00:00:30 1970 +0000
495 | | | | | date: Thu Jan 01 00:00:30 1970 +0000
496 | | | | | summary: (30) expand
496 | | | | | summary: (30) expand
497 | | | | |
497 | | | | |
498 | | | o | changeset: 29:cd9bb2be7593
498 | | | o | changeset: 29:cd9bb2be7593
499 | | | | | parent: 0:e6eb3150255d
499 | | | | | parent: 0:e6eb3150255d
500 | | | | | user: test
500 | | | | | user: test
501 | | | | | date: Thu Jan 01 00:00:29 1970 +0000
501 | | | | | date: Thu Jan 01 00:00:29 1970 +0000
502 | | | | | summary: (29) regular commit
502 | | | | | summary: (29) regular commit
503 | | | | |
503 | | | | |
504 | | o | | changeset: 28:44ecd0b9ae99
504 | | o | | changeset: 28:44ecd0b9ae99
505 | | |\ \ \ parent: 1:6db2ef61d156
505 | | |\ \ \ parent: 1:6db2ef61d156
506 | | | | | | parent: 26:7f25b6c2f0b9
506 | | | | | | parent: 26:7f25b6c2f0b9
507 | | | | | | user: test
507 | | | | | | user: test
508 | | | | | | date: Thu Jan 01 00:00:28 1970 +0000
508 | | | | | | date: Thu Jan 01 00:00:28 1970 +0000
509 | | | | | | summary: (28) merge zero known
509 | | | | | | summary: (28) merge zero known
510 | | | | | |
510 | | | | | |
511 o | | | | | changeset: 27:886ed638191b
511 o | | | | | changeset: 27:886ed638191b
512 |/ / / / / parent: 21:d42a756af44d
512 |/ / / / / parent: 21:d42a756af44d
513 | | | | | user: test
513 | | | | | user: test
514 | | | | | date: Thu Jan 01 00:00:27 1970 +0000
514 | | | | | date: Thu Jan 01 00:00:27 1970 +0000
515 | | | | | summary: (27) collapse
515 | | | | | summary: (27) collapse
516 | | | | |
516 | | | | |
517 | | o---+ changeset: 26:7f25b6c2f0b9
517 | | o---+ changeset: 26:7f25b6c2f0b9
518 | | | | | parent: 18:1aa84d96232a
518 | | | | | parent: 18:1aa84d96232a
519 | | | | | parent: 25:91da8ed57247
519 | | | | | parent: 25:91da8ed57247
520 | | | | | user: test
520 | | | | | user: test
521 | | | | | date: Thu Jan 01 00:00:26 1970 +0000
521 | | | | | date: Thu Jan 01 00:00:26 1970 +0000
522 | | | | | summary: (26) merge one known; far right
522 | | | | | summary: (26) merge one known; far right
523 | | | | |
523 | | | | |
524 +---o | | changeset: 25:91da8ed57247
524 +---o | | changeset: 25:91da8ed57247
525 | | | | | parent: 21:d42a756af44d
525 | | | | | parent: 21:d42a756af44d
526 | | | | | parent: 24:a9c19a3d96b7
526 | | | | | parent: 24:a9c19a3d96b7
527 | | | | | user: test
527 | | | | | user: test
528 | | | | | date: Thu Jan 01 00:00:25 1970 +0000
528 | | | | | date: Thu Jan 01 00:00:25 1970 +0000
529 | | | | | summary: (25) merge one known; far left
529 | | | | | summary: (25) merge one known; far left
530 | | | | |
530 | | | | |
531 | | o | | changeset: 24:a9c19a3d96b7
531 | | o | | changeset: 24:a9c19a3d96b7
532 | | |\| | parent: 0:e6eb3150255d
532 | | |\| | parent: 0:e6eb3150255d
533 | | | | | parent: 23:a01cddf0766d
533 | | | | | parent: 23:a01cddf0766d
534 | | | | | user: test
534 | | | | | user: test
535 | | | | | date: Thu Jan 01 00:00:24 1970 +0000
535 | | | | | date: Thu Jan 01 00:00:24 1970 +0000
536 | | | | | summary: (24) merge one known; immediate right
536 | | | | | summary: (24) merge one known; immediate right
537 | | | | |
537 | | | | |
538 | | o | | changeset: 23:a01cddf0766d
538 | | o | | changeset: 23:a01cddf0766d
539 | |/| | | parent: 1:6db2ef61d156
539 | |/| | | parent: 1:6db2ef61d156
540 | | | | | parent: 22:e0d9cccacb5d
540 | | | | | parent: 22:e0d9cccacb5d
541 | | | | | user: test
541 | | | | | user: test
542 | | | | | date: Thu Jan 01 00:00:23 1970 +0000
542 | | | | | date: Thu Jan 01 00:00:23 1970 +0000
543 | | | | | summary: (23) merge one known; immediate left
543 | | | | | summary: (23) merge one known; immediate left
544 | | | | |
544 | | | | |
545 +---o---+ changeset: 22:e0d9cccacb5d
545 +---o---+ changeset: 22:e0d9cccacb5d
546 | | | | parent: 18:1aa84d96232a
546 | | | | parent: 18:1aa84d96232a
547 | | / / parent: 21:d42a756af44d
547 | | / / parent: 21:d42a756af44d
548 | | | | user: test
548 | | | | user: test
549 | | | | date: Thu Jan 01 00:00:22 1970 +0000
549 | | | | date: Thu Jan 01 00:00:22 1970 +0000
550 | | | | summary: (22) merge two known; one far left, one far right
550 | | | | summary: (22) merge two known; one far left, one far right
551 | | | |
551 | | | |
552 o | | | changeset: 21:d42a756af44d
552 o | | | changeset: 21:d42a756af44d
553 |\ \ \ \ parent: 19:31ddc2c1573b
553 |\ \ \ \ parent: 19:31ddc2c1573b
554 | | | | | parent: 20:d30ed6450e32
554 | | | | | parent: 20:d30ed6450e32
555 | | | | | user: test
555 | | | | | user: test
556 | | | | | date: Thu Jan 01 00:00:21 1970 +0000
556 | | | | | date: Thu Jan 01 00:00:21 1970 +0000
557 | | | | | summary: (21) expand
557 | | | | | summary: (21) expand
558 | | | | |
558 | | | | |
559 | o---+-+ changeset: 20:d30ed6450e32
559 | o---+-+ changeset: 20:d30ed6450e32
560 | | | | parent: 0:e6eb3150255d
560 | | | | parent: 0:e6eb3150255d
561 | / / / parent: 18:1aa84d96232a
561 | / / / parent: 18:1aa84d96232a
562 | | | | user: test
562 | | | | user: test
563 | | | | date: Thu Jan 01 00:00:20 1970 +0000
563 | | | | date: Thu Jan 01 00:00:20 1970 +0000
564 | | | | summary: (20) merge two known; two far right
564 | | | | summary: (20) merge two known; two far right
565 | | | |
565 | | | |
566 o | | | changeset: 19:31ddc2c1573b
566 o | | | changeset: 19:31ddc2c1573b
567 |\ \ \ \ parent: 15:1dda3f72782d
567 |\ \ \ \ parent: 15:1dda3f72782d
568 | | | | | parent: 17:44765d7c06e0
568 | | | | | parent: 17:44765d7c06e0
569 | | | | | user: test
569 | | | | | user: test
570 | | | | | date: Thu Jan 01 00:00:19 1970 +0000
570 | | | | | date: Thu Jan 01 00:00:19 1970 +0000
571 | | | | | summary: (19) expand
571 | | | | | summary: (19) expand
572 | | | | |
572 | | | | |
573 +---+---o changeset: 18:1aa84d96232a
573 +---+---o changeset: 18:1aa84d96232a
574 | | | | parent: 1:6db2ef61d156
574 | | | | parent: 1:6db2ef61d156
575 | | | | parent: 15:1dda3f72782d
575 | | | | parent: 15:1dda3f72782d
576 | | | | user: test
576 | | | | user: test
577 | | | | date: Thu Jan 01 00:00:18 1970 +0000
577 | | | | date: Thu Jan 01 00:00:18 1970 +0000
578 | | | | summary: (18) merge two known; two far left
578 | | | | summary: (18) merge two known; two far left
579 | | | |
579 | | | |
580 | o | | changeset: 17:44765d7c06e0
580 | o | | changeset: 17:44765d7c06e0
581 | |\ \ \ parent: 12:86b91144a6e9
581 | |\ \ \ parent: 12:86b91144a6e9
582 | | | | | parent: 16:3677d192927d
582 | | | | | parent: 16:3677d192927d
583 | | | | | user: test
583 | | | | | user: test
584 | | | | | date: Thu Jan 01 00:00:17 1970 +0000
584 | | | | | date: Thu Jan 01 00:00:17 1970 +0000
585 | | | | | summary: (17) expand
585 | | | | | summary: (17) expand
586 | | | | |
586 | | | | |
587 | | o---+ changeset: 16:3677d192927d
587 | | o---+ changeset: 16:3677d192927d
588 | | | | | parent: 0:e6eb3150255d
588 | | | | | parent: 0:e6eb3150255d
589 | | |/ / parent: 1:6db2ef61d156
589 | | |/ / parent: 1:6db2ef61d156
590 | | | | user: test
590 | | | | user: test
591 | | | | date: Thu Jan 01 00:00:16 1970 +0000
591 | | | | date: Thu Jan 01 00:00:16 1970 +0000
592 | | | | summary: (16) merge two known; one immediate right, one near right
592 | | | | summary: (16) merge two known; one immediate right, one near right
593 | | | |
593 | | | |
594 o | | | changeset: 15:1dda3f72782d
594 o | | | changeset: 15:1dda3f72782d
595 |\ \ \ \ parent: 13:22d8966a97e3
595 |\ \ \ \ parent: 13:22d8966a97e3
596 | | | | | parent: 14:8eac370358ef
596 | | | | | parent: 14:8eac370358ef
597 | | | | | user: test
597 | | | | | user: test
598 | | | | | date: Thu Jan 01 00:00:15 1970 +0000
598 | | | | | date: Thu Jan 01 00:00:15 1970 +0000
599 | | | | | summary: (15) expand
599 | | | | | summary: (15) expand
600 | | | | |
600 | | | | |
601 | o-----+ changeset: 14:8eac370358ef
601 | o-----+ changeset: 14:8eac370358ef
602 | | | | | parent: 0:e6eb3150255d
602 | | | | | parent: 0:e6eb3150255d
603 | |/ / / parent: 12:86b91144a6e9
603 | |/ / / parent: 12:86b91144a6e9
604 | | | | user: test
604 | | | | user: test
605 | | | | date: Thu Jan 01 00:00:14 1970 +0000
605 | | | | date: Thu Jan 01 00:00:14 1970 +0000
606 | | | | summary: (14) merge two known; one immediate right, one far right
606 | | | | summary: (14) merge two known; one immediate right, one far right
607 | | | |
607 | | | |
608 o | | | changeset: 13:22d8966a97e3
608 o | | | changeset: 13:22d8966a97e3
609 |\ \ \ \ parent: 9:7010c0af0a35
609 |\ \ \ \ parent: 9:7010c0af0a35
610 | | | | | parent: 11:832d76e6bdf2
610 | | | | | parent: 11:832d76e6bdf2
611 | | | | | user: test
611 | | | | | user: test
612 | | | | | date: Thu Jan 01 00:00:13 1970 +0000
612 | | | | | date: Thu Jan 01 00:00:13 1970 +0000
613 | | | | | summary: (13) expand
613 | | | | | summary: (13) expand
614 | | | | |
614 | | | | |
615 +---o | | changeset: 12:86b91144a6e9
615 +---o | | changeset: 12:86b91144a6e9
616 | | |/ / parent: 1:6db2ef61d156
616 | | |/ / parent: 1:6db2ef61d156
617 | | | | parent: 9:7010c0af0a35
617 | | | | parent: 9:7010c0af0a35
618 | | | | user: test
618 | | | | user: test
619 | | | | date: Thu Jan 01 00:00:12 1970 +0000
619 | | | | date: Thu Jan 01 00:00:12 1970 +0000
620 | | | | summary: (12) merge two known; one immediate right, one far left
620 | | | | summary: (12) merge two known; one immediate right, one far left
621 | | | |
621 | | | |
622 | o | | changeset: 11:832d76e6bdf2
622 | o | | changeset: 11:832d76e6bdf2
623 | |\ \ \ parent: 6:b105a072e251
623 | |\ \ \ parent: 6:b105a072e251
624 | | | | | parent: 10:74c64d036d72
624 | | | | | parent: 10:74c64d036d72
625 | | | | | user: test
625 | | | | | user: test
626 | | | | | date: Thu Jan 01 00:00:11 1970 +0000
626 | | | | | date: Thu Jan 01 00:00:11 1970 +0000
627 | | | | | summary: (11) expand
627 | | | | | summary: (11) expand
628 | | | | |
628 | | | | |
629 | | o---+ changeset: 10:74c64d036d72
629 | | o---+ changeset: 10:74c64d036d72
630 | | | | | parent: 0:e6eb3150255d
630 | | | | | parent: 0:e6eb3150255d
631 | |/ / / parent: 6:b105a072e251
631 | |/ / / parent: 6:b105a072e251
632 | | | | user: test
632 | | | | user: test
633 | | | | date: Thu Jan 01 00:00:10 1970 +0000
633 | | | | date: Thu Jan 01 00:00:10 1970 +0000
634 | | | | summary: (10) merge two known; one immediate left, one near right
634 | | | | summary: (10) merge two known; one immediate left, one near right
635 | | | |
635 | | | |
636 o | | | changeset: 9:7010c0af0a35
636 o | | | changeset: 9:7010c0af0a35
637 |\ \ \ \ parent: 7:b632bb1b1224
637 |\ \ \ \ parent: 7:b632bb1b1224
638 | | | | | parent: 8:7a0b11f71937
638 | | | | | parent: 8:7a0b11f71937
639 | | | | | user: test
639 | | | | | user: test
640 | | | | | date: Thu Jan 01 00:00:09 1970 +0000
640 | | | | | date: Thu Jan 01 00:00:09 1970 +0000
641 | | | | | summary: (9) expand
641 | | | | | summary: (9) expand
642 | | | | |
642 | | | | |
643 | o-----+ changeset: 8:7a0b11f71937
643 | o-----+ changeset: 8:7a0b11f71937
644 | | | | | parent: 0:e6eb3150255d
644 | | | | | parent: 0:e6eb3150255d
645 |/ / / / parent: 7:b632bb1b1224
645 |/ / / / parent: 7:b632bb1b1224
646 | | | | user: test
646 | | | | user: test
647 | | | | date: Thu Jan 01 00:00:08 1970 +0000
647 | | | | date: Thu Jan 01 00:00:08 1970 +0000
648 | | | | summary: (8) merge two known; one immediate left, one far right
648 | | | | summary: (8) merge two known; one immediate left, one far right
649 | | | |
649 | | | |
650 o | | | changeset: 7:b632bb1b1224
650 o | | | changeset: 7:b632bb1b1224
651 |\ \ \ \ parent: 2:3d9a33b8d1e1
651 |\ \ \ \ parent: 2:3d9a33b8d1e1
652 | | | | | parent: 5:4409d547b708
652 | | | | | parent: 5:4409d547b708
653 | | | | | user: test
653 | | | | | user: test
654 | | | | | date: Thu Jan 01 00:00:07 1970 +0000
654 | | | | | date: Thu Jan 01 00:00:07 1970 +0000
655 | | | | | summary: (7) expand
655 | | | | | summary: (7) expand
656 | | | | |
656 | | | | |
657 +---o | | changeset: 6:b105a072e251
657 +---o | | changeset: 6:b105a072e251
658 | |/ / / parent: 2:3d9a33b8d1e1
658 | |/ / / parent: 2:3d9a33b8d1e1
659 | | | | parent: 5:4409d547b708
659 | | | | parent: 5:4409d547b708
660 | | | | user: test
660 | | | | user: test
661 | | | | date: Thu Jan 01 00:00:06 1970 +0000
661 | | | | date: Thu Jan 01 00:00:06 1970 +0000
662 | | | | summary: (6) merge two known; one immediate left, one far left
662 | | | | summary: (6) merge two known; one immediate left, one far left
663 | | | |
663 | | | |
664 | o | | changeset: 5:4409d547b708
664 | o | | changeset: 5:4409d547b708
665 | |\ \ \ parent: 3:27eef8ed80b4
665 | |\ \ \ parent: 3:27eef8ed80b4
666 | | | | | parent: 4:26a8bac39d9f
666 | | | | | parent: 4:26a8bac39d9f
667 | | | | | user: test
667 | | | | | user: test
668 | | | | | date: Thu Jan 01 00:00:05 1970 +0000
668 | | | | | date: Thu Jan 01 00:00:05 1970 +0000
669 | | | | | summary: (5) expand
669 | | | | | summary: (5) expand
670 | | | | |
670 | | | | |
671 | | o | | changeset: 4:26a8bac39d9f
671 | | o | | changeset: 4:26a8bac39d9f
672 | |/|/ / parent: 1:6db2ef61d156
672 | |/|/ / parent: 1:6db2ef61d156
673 | | | | parent: 3:27eef8ed80b4
673 | | | | parent: 3:27eef8ed80b4
674 | | | | user: test
674 | | | | user: test
675 | | | | date: Thu Jan 01 00:00:04 1970 +0000
675 | | | | date: Thu Jan 01 00:00:04 1970 +0000
676 | | | | summary: (4) merge two known; one immediate left, one immediate right
676 | | | | summary: (4) merge two known; one immediate left, one immediate right
677 | | | |
677 | | | |
678 | o | | changeset: 3:27eef8ed80b4
678 | o | | changeset: 3:27eef8ed80b4
679 |/ / / user: test
679 |/ / / user: test
680 | | | date: Thu Jan 01 00:00:03 1970 +0000
680 | | | date: Thu Jan 01 00:00:03 1970 +0000
681 | | | summary: (3) collapse
681 | | | summary: (3) collapse
682 | | |
682 | | |
683 o | | changeset: 2:3d9a33b8d1e1
683 o | | changeset: 2:3d9a33b8d1e1
684 |/ / user: test
684 |/ / user: test
685 | | date: Thu Jan 01 00:00:02 1970 +0000
685 | | date: Thu Jan 01 00:00:02 1970 +0000
686 | | summary: (2) collapse
686 | | summary: (2) collapse
687 | |
687 | |
688 o | changeset: 1:6db2ef61d156
688 o | changeset: 1:6db2ef61d156
689 |/ user: test
689 |/ user: test
690 | date: Thu Jan 01 00:00:01 1970 +0000
690 | date: Thu Jan 01 00:00:01 1970 +0000
691 | summary: (1) collapse
691 | summary: (1) collapse
692 |
692 |
693 o changeset: 0:e6eb3150255d
693 o changeset: 0:e6eb3150255d
694 user: test
694 user: test
695 date: Thu Jan 01 00:00:00 1970 +0000
695 date: Thu Jan 01 00:00:00 1970 +0000
696 summary: (0) root
696 summary: (0) root
697
697
698
698
699 File glog per revset:
699 File glog per revset:
700
700
701 $ hg log -G -r 'file("a")'
701 $ hg log -G -r 'file("a")'
702 @ changeset: 34:fea3ac5810e0
702 @ changeset: 34:fea3ac5810e0
703 | tag: tip
703 | tag: tip
704 | parent: 32:d06dffa21a31
704 | parent: 32:d06dffa21a31
705 | user: test
705 | user: test
706 | date: Thu Jan 01 00:00:34 1970 +0000
706 | date: Thu Jan 01 00:00:34 1970 +0000
707 | summary: (34) head
707 | summary: (34) head
708 |
708 |
709 | o changeset: 33:68608f5145f9
709 | o changeset: 33:68608f5145f9
710 | | parent: 18:1aa84d96232a
710 | | parent: 18:1aa84d96232a
711 | | user: test
711 | | user: test
712 | | date: Thu Jan 01 00:00:33 1970 +0000
712 | | date: Thu Jan 01 00:00:33 1970 +0000
713 | | summary: (33) head
713 | | summary: (33) head
714 | |
714 | |
715 o | changeset: 32:d06dffa21a31
715 o | changeset: 32:d06dffa21a31
716 |\ \ parent: 27:886ed638191b
716 |\ \ parent: 27:886ed638191b
717 | | | parent: 31:621d83e11f67
717 | | | parent: 31:621d83e11f67
718 | | | user: test
718 | | | user: test
719 | | | date: Thu Jan 01 00:00:32 1970 +0000
719 | | | date: Thu Jan 01 00:00:32 1970 +0000
720 | | | summary: (32) expand
720 | | | summary: (32) expand
721 | | |
721 | | |
722 | o | changeset: 31:621d83e11f67
722 | o | changeset: 31:621d83e11f67
723 | |\ \ parent: 21:d42a756af44d
723 | |\ \ parent: 21:d42a756af44d
724 | | | | parent: 30:6e11cd4b648f
724 | | | | parent: 30:6e11cd4b648f
725 | | | | user: test
725 | | | | user: test
726 | | | | date: Thu Jan 01 00:00:31 1970 +0000
726 | | | | date: Thu Jan 01 00:00:31 1970 +0000
727 | | | | summary: (31) expand
727 | | | | summary: (31) expand
728 | | | |
728 | | | |
729 | | o | changeset: 30:6e11cd4b648f
729 | | o | changeset: 30:6e11cd4b648f
730 | | |\ \ parent: 28:44ecd0b9ae99
730 | | |\ \ parent: 28:44ecd0b9ae99
731 | | | | | parent: 29:cd9bb2be7593
731 | | | | | parent: 29:cd9bb2be7593
732 | | | | | user: test
732 | | | | | user: test
733 | | | | | date: Thu Jan 01 00:00:30 1970 +0000
733 | | | | | date: Thu Jan 01 00:00:30 1970 +0000
734 | | | | | summary: (30) expand
734 | | | | | summary: (30) expand
735 | | | | |
735 | | | | |
736 | | | o | changeset: 29:cd9bb2be7593
736 | | | o | changeset: 29:cd9bb2be7593
737 | | | | | parent: 0:e6eb3150255d
737 | | | | | parent: 0:e6eb3150255d
738 | | | | | user: test
738 | | | | | user: test
739 | | | | | date: Thu Jan 01 00:00:29 1970 +0000
739 | | | | | date: Thu Jan 01 00:00:29 1970 +0000
740 | | | | | summary: (29) regular commit
740 | | | | | summary: (29) regular commit
741 | | | | |
741 | | | | |
742 | | o | | changeset: 28:44ecd0b9ae99
742 | | o | | changeset: 28:44ecd0b9ae99
743 | | |\ \ \ parent: 1:6db2ef61d156
743 | | |\ \ \ parent: 1:6db2ef61d156
744 | | | | | | parent: 26:7f25b6c2f0b9
744 | | | | | | parent: 26:7f25b6c2f0b9
745 | | | | | | user: test
745 | | | | | | user: test
746 | | | | | | date: Thu Jan 01 00:00:28 1970 +0000
746 | | | | | | date: Thu Jan 01 00:00:28 1970 +0000
747 | | | | | | summary: (28) merge zero known
747 | | | | | | summary: (28) merge zero known
748 | | | | | |
748 | | | | | |
749 o | | | | | changeset: 27:886ed638191b
749 o | | | | | changeset: 27:886ed638191b
750 |/ / / / / parent: 21:d42a756af44d
750 |/ / / / / parent: 21:d42a756af44d
751 | | | | | user: test
751 | | | | | user: test
752 | | | | | date: Thu Jan 01 00:00:27 1970 +0000
752 | | | | | date: Thu Jan 01 00:00:27 1970 +0000
753 | | | | | summary: (27) collapse
753 | | | | | summary: (27) collapse
754 | | | | |
754 | | | | |
755 | | o---+ changeset: 26:7f25b6c2f0b9
755 | | o---+ changeset: 26:7f25b6c2f0b9
756 | | | | | parent: 18:1aa84d96232a
756 | | | | | parent: 18:1aa84d96232a
757 | | | | | parent: 25:91da8ed57247
757 | | | | | parent: 25:91da8ed57247
758 | | | | | user: test
758 | | | | | user: test
759 | | | | | date: Thu Jan 01 00:00:26 1970 +0000
759 | | | | | date: Thu Jan 01 00:00:26 1970 +0000
760 | | | | | summary: (26) merge one known; far right
760 | | | | | summary: (26) merge one known; far right
761 | | | | |
761 | | | | |
762 +---o | | changeset: 25:91da8ed57247
762 +---o | | changeset: 25:91da8ed57247
763 | | | | | parent: 21:d42a756af44d
763 | | | | | parent: 21:d42a756af44d
764 | | | | | parent: 24:a9c19a3d96b7
764 | | | | | parent: 24:a9c19a3d96b7
765 | | | | | user: test
765 | | | | | user: test
766 | | | | | date: Thu Jan 01 00:00:25 1970 +0000
766 | | | | | date: Thu Jan 01 00:00:25 1970 +0000
767 | | | | | summary: (25) merge one known; far left
767 | | | | | summary: (25) merge one known; far left
768 | | | | |
768 | | | | |
769 | | o | | changeset: 24:a9c19a3d96b7
769 | | o | | changeset: 24:a9c19a3d96b7
770 | | |\| | parent: 0:e6eb3150255d
770 | | |\| | parent: 0:e6eb3150255d
771 | | | | | parent: 23:a01cddf0766d
771 | | | | | parent: 23:a01cddf0766d
772 | | | | | user: test
772 | | | | | user: test
773 | | | | | date: Thu Jan 01 00:00:24 1970 +0000
773 | | | | | date: Thu Jan 01 00:00:24 1970 +0000
774 | | | | | summary: (24) merge one known; immediate right
774 | | | | | summary: (24) merge one known; immediate right
775 | | | | |
775 | | | | |
776 | | o | | changeset: 23:a01cddf0766d
776 | | o | | changeset: 23:a01cddf0766d
777 | |/| | | parent: 1:6db2ef61d156
777 | |/| | | parent: 1:6db2ef61d156
778 | | | | | parent: 22:e0d9cccacb5d
778 | | | | | parent: 22:e0d9cccacb5d
779 | | | | | user: test
779 | | | | | user: test
780 | | | | | date: Thu Jan 01 00:00:23 1970 +0000
780 | | | | | date: Thu Jan 01 00:00:23 1970 +0000
781 | | | | | summary: (23) merge one known; immediate left
781 | | | | | summary: (23) merge one known; immediate left
782 | | | | |
782 | | | | |
783 +---o---+ changeset: 22:e0d9cccacb5d
783 +---o---+ changeset: 22:e0d9cccacb5d
784 | | | | parent: 18:1aa84d96232a
784 | | | | parent: 18:1aa84d96232a
785 | | / / parent: 21:d42a756af44d
785 | | / / parent: 21:d42a756af44d
786 | | | | user: test
786 | | | | user: test
787 | | | | date: Thu Jan 01 00:00:22 1970 +0000
787 | | | | date: Thu Jan 01 00:00:22 1970 +0000
788 | | | | summary: (22) merge two known; one far left, one far right
788 | | | | summary: (22) merge two known; one far left, one far right
789 | | | |
789 | | | |
790 o | | | changeset: 21:d42a756af44d
790 o | | | changeset: 21:d42a756af44d
791 |\ \ \ \ parent: 19:31ddc2c1573b
791 |\ \ \ \ parent: 19:31ddc2c1573b
792 | | | | | parent: 20:d30ed6450e32
792 | | | | | parent: 20:d30ed6450e32
793 | | | | | user: test
793 | | | | | user: test
794 | | | | | date: Thu Jan 01 00:00:21 1970 +0000
794 | | | | | date: Thu Jan 01 00:00:21 1970 +0000
795 | | | | | summary: (21) expand
795 | | | | | summary: (21) expand
796 | | | | |
796 | | | | |
797 | o---+-+ changeset: 20:d30ed6450e32
797 | o---+-+ changeset: 20:d30ed6450e32
798 | | | | parent: 0:e6eb3150255d
798 | | | | parent: 0:e6eb3150255d
799 | / / / parent: 18:1aa84d96232a
799 | / / / parent: 18:1aa84d96232a
800 | | | | user: test
800 | | | | user: test
801 | | | | date: Thu Jan 01 00:00:20 1970 +0000
801 | | | | date: Thu Jan 01 00:00:20 1970 +0000
802 | | | | summary: (20) merge two known; two far right
802 | | | | summary: (20) merge two known; two far right
803 | | | |
803 | | | |
804 o | | | changeset: 19:31ddc2c1573b
804 o | | | changeset: 19:31ddc2c1573b
805 |\ \ \ \ parent: 15:1dda3f72782d
805 |\ \ \ \ parent: 15:1dda3f72782d
806 | | | | | parent: 17:44765d7c06e0
806 | | | | | parent: 17:44765d7c06e0
807 | | | | | user: test
807 | | | | | user: test
808 | | | | | date: Thu Jan 01 00:00:19 1970 +0000
808 | | | | | date: Thu Jan 01 00:00:19 1970 +0000
809 | | | | | summary: (19) expand
809 | | | | | summary: (19) expand
810 | | | | |
810 | | | | |
811 +---+---o changeset: 18:1aa84d96232a
811 +---+---o changeset: 18:1aa84d96232a
812 | | | | parent: 1:6db2ef61d156
812 | | | | parent: 1:6db2ef61d156
813 | | | | parent: 15:1dda3f72782d
813 | | | | parent: 15:1dda3f72782d
814 | | | | user: test
814 | | | | user: test
815 | | | | date: Thu Jan 01 00:00:18 1970 +0000
815 | | | | date: Thu Jan 01 00:00:18 1970 +0000
816 | | | | summary: (18) merge two known; two far left
816 | | | | summary: (18) merge two known; two far left
817 | | | |
817 | | | |
818 | o | | changeset: 17:44765d7c06e0
818 | o | | changeset: 17:44765d7c06e0
819 | |\ \ \ parent: 12:86b91144a6e9
819 | |\ \ \ parent: 12:86b91144a6e9
820 | | | | | parent: 16:3677d192927d
820 | | | | | parent: 16:3677d192927d
821 | | | | | user: test
821 | | | | | user: test
822 | | | | | date: Thu Jan 01 00:00:17 1970 +0000
822 | | | | | date: Thu Jan 01 00:00:17 1970 +0000
823 | | | | | summary: (17) expand
823 | | | | | summary: (17) expand
824 | | | | |
824 | | | | |
825 | | o---+ changeset: 16:3677d192927d
825 | | o---+ changeset: 16:3677d192927d
826 | | | | | parent: 0:e6eb3150255d
826 | | | | | parent: 0:e6eb3150255d
827 | | |/ / parent: 1:6db2ef61d156
827 | | |/ / parent: 1:6db2ef61d156
828 | | | | user: test
828 | | | | user: test
829 | | | | date: Thu Jan 01 00:00:16 1970 +0000
829 | | | | date: Thu Jan 01 00:00:16 1970 +0000
830 | | | | summary: (16) merge two known; one immediate right, one near right
830 | | | | summary: (16) merge two known; one immediate right, one near right
831 | | | |
831 | | | |
832 o | | | changeset: 15:1dda3f72782d
832 o | | | changeset: 15:1dda3f72782d
833 |\ \ \ \ parent: 13:22d8966a97e3
833 |\ \ \ \ parent: 13:22d8966a97e3
834 | | | | | parent: 14:8eac370358ef
834 | | | | | parent: 14:8eac370358ef
835 | | | | | user: test
835 | | | | | user: test
836 | | | | | date: Thu Jan 01 00:00:15 1970 +0000
836 | | | | | date: Thu Jan 01 00:00:15 1970 +0000
837 | | | | | summary: (15) expand
837 | | | | | summary: (15) expand
838 | | | | |
838 | | | | |
839 | o-----+ changeset: 14:8eac370358ef
839 | o-----+ changeset: 14:8eac370358ef
840 | | | | | parent: 0:e6eb3150255d
840 | | | | | parent: 0:e6eb3150255d
841 | |/ / / parent: 12:86b91144a6e9
841 | |/ / / parent: 12:86b91144a6e9
842 | | | | user: test
842 | | | | user: test
843 | | | | date: Thu Jan 01 00:00:14 1970 +0000
843 | | | | date: Thu Jan 01 00:00:14 1970 +0000
844 | | | | summary: (14) merge two known; one immediate right, one far right
844 | | | | summary: (14) merge two known; one immediate right, one far right
845 | | | |
845 | | | |
846 o | | | changeset: 13:22d8966a97e3
846 o | | | changeset: 13:22d8966a97e3
847 |\ \ \ \ parent: 9:7010c0af0a35
847 |\ \ \ \ parent: 9:7010c0af0a35
848 | | | | | parent: 11:832d76e6bdf2
848 | | | | | parent: 11:832d76e6bdf2
849 | | | | | user: test
849 | | | | | user: test
850 | | | | | date: Thu Jan 01 00:00:13 1970 +0000
850 | | | | | date: Thu Jan 01 00:00:13 1970 +0000
851 | | | | | summary: (13) expand
851 | | | | | summary: (13) expand
852 | | | | |
852 | | | | |
853 +---o | | changeset: 12:86b91144a6e9
853 +---o | | changeset: 12:86b91144a6e9
854 | | |/ / parent: 1:6db2ef61d156
854 | | |/ / parent: 1:6db2ef61d156
855 | | | | parent: 9:7010c0af0a35
855 | | | | parent: 9:7010c0af0a35
856 | | | | user: test
856 | | | | user: test
857 | | | | date: Thu Jan 01 00:00:12 1970 +0000
857 | | | | date: Thu Jan 01 00:00:12 1970 +0000
858 | | | | summary: (12) merge two known; one immediate right, one far left
858 | | | | summary: (12) merge two known; one immediate right, one far left
859 | | | |
859 | | | |
860 | o | | changeset: 11:832d76e6bdf2
860 | o | | changeset: 11:832d76e6bdf2
861 | |\ \ \ parent: 6:b105a072e251
861 | |\ \ \ parent: 6:b105a072e251
862 | | | | | parent: 10:74c64d036d72
862 | | | | | parent: 10:74c64d036d72
863 | | | | | user: test
863 | | | | | user: test
864 | | | | | date: Thu Jan 01 00:00:11 1970 +0000
864 | | | | | date: Thu Jan 01 00:00:11 1970 +0000
865 | | | | | summary: (11) expand
865 | | | | | summary: (11) expand
866 | | | | |
866 | | | | |
867 | | o---+ changeset: 10:74c64d036d72
867 | | o---+ changeset: 10:74c64d036d72
868 | | | | | parent: 0:e6eb3150255d
868 | | | | | parent: 0:e6eb3150255d
869 | |/ / / parent: 6:b105a072e251
869 | |/ / / parent: 6:b105a072e251
870 | | | | user: test
870 | | | | user: test
871 | | | | date: Thu Jan 01 00:00:10 1970 +0000
871 | | | | date: Thu Jan 01 00:00:10 1970 +0000
872 | | | | summary: (10) merge two known; one immediate left, one near right
872 | | | | summary: (10) merge two known; one immediate left, one near right
873 | | | |
873 | | | |
874 o | | | changeset: 9:7010c0af0a35
874 o | | | changeset: 9:7010c0af0a35
875 |\ \ \ \ parent: 7:b632bb1b1224
875 |\ \ \ \ parent: 7:b632bb1b1224
876 | | | | | parent: 8:7a0b11f71937
876 | | | | | parent: 8:7a0b11f71937
877 | | | | | user: test
877 | | | | | user: test
878 | | | | | date: Thu Jan 01 00:00:09 1970 +0000
878 | | | | | date: Thu Jan 01 00:00:09 1970 +0000
879 | | | | | summary: (9) expand
879 | | | | | summary: (9) expand
880 | | | | |
880 | | | | |
881 | o-----+ changeset: 8:7a0b11f71937
881 | o-----+ changeset: 8:7a0b11f71937
882 | | | | | parent: 0:e6eb3150255d
882 | | | | | parent: 0:e6eb3150255d
883 |/ / / / parent: 7:b632bb1b1224
883 |/ / / / parent: 7:b632bb1b1224
884 | | | | user: test
884 | | | | user: test
885 | | | | date: Thu Jan 01 00:00:08 1970 +0000
885 | | | | date: Thu Jan 01 00:00:08 1970 +0000
886 | | | | summary: (8) merge two known; one immediate left, one far right
886 | | | | summary: (8) merge two known; one immediate left, one far right
887 | | | |
887 | | | |
888 o | | | changeset: 7:b632bb1b1224
888 o | | | changeset: 7:b632bb1b1224
889 |\ \ \ \ parent: 2:3d9a33b8d1e1
889 |\ \ \ \ parent: 2:3d9a33b8d1e1
890 | | | | | parent: 5:4409d547b708
890 | | | | | parent: 5:4409d547b708
891 | | | | | user: test
891 | | | | | user: test
892 | | | | | date: Thu Jan 01 00:00:07 1970 +0000
892 | | | | | date: Thu Jan 01 00:00:07 1970 +0000
893 | | | | | summary: (7) expand
893 | | | | | summary: (7) expand
894 | | | | |
894 | | | | |
895 +---o | | changeset: 6:b105a072e251
895 +---o | | changeset: 6:b105a072e251
896 | |/ / / parent: 2:3d9a33b8d1e1
896 | |/ / / parent: 2:3d9a33b8d1e1
897 | | | | parent: 5:4409d547b708
897 | | | | parent: 5:4409d547b708
898 | | | | user: test
898 | | | | user: test
899 | | | | date: Thu Jan 01 00:00:06 1970 +0000
899 | | | | date: Thu Jan 01 00:00:06 1970 +0000
900 | | | | summary: (6) merge two known; one immediate left, one far left
900 | | | | summary: (6) merge two known; one immediate left, one far left
901 | | | |
901 | | | |
902 | o | | changeset: 5:4409d547b708
902 | o | | changeset: 5:4409d547b708
903 | |\ \ \ parent: 3:27eef8ed80b4
903 | |\ \ \ parent: 3:27eef8ed80b4
904 | | | | | parent: 4:26a8bac39d9f
904 | | | | | parent: 4:26a8bac39d9f
905 | | | | | user: test
905 | | | | | user: test
906 | | | | | date: Thu Jan 01 00:00:05 1970 +0000
906 | | | | | date: Thu Jan 01 00:00:05 1970 +0000
907 | | | | | summary: (5) expand
907 | | | | | summary: (5) expand
908 | | | | |
908 | | | | |
909 | | o | | changeset: 4:26a8bac39d9f
909 | | o | | changeset: 4:26a8bac39d9f
910 | |/|/ / parent: 1:6db2ef61d156
910 | |/|/ / parent: 1:6db2ef61d156
911 | | | | parent: 3:27eef8ed80b4
911 | | | | parent: 3:27eef8ed80b4
912 | | | | user: test
912 | | | | user: test
913 | | | | date: Thu Jan 01 00:00:04 1970 +0000
913 | | | | date: Thu Jan 01 00:00:04 1970 +0000
914 | | | | summary: (4) merge two known; one immediate left, one immediate right
914 | | | | summary: (4) merge two known; one immediate left, one immediate right
915 | | | |
915 | | | |
916 | o | | changeset: 3:27eef8ed80b4
916 | o | | changeset: 3:27eef8ed80b4
917 |/ / / user: test
917 |/ / / user: test
918 | | | date: Thu Jan 01 00:00:03 1970 +0000
918 | | | date: Thu Jan 01 00:00:03 1970 +0000
919 | | | summary: (3) collapse
919 | | | summary: (3) collapse
920 | | |
920 | | |
921 o | | changeset: 2:3d9a33b8d1e1
921 o | | changeset: 2:3d9a33b8d1e1
922 |/ / user: test
922 |/ / user: test
923 | | date: Thu Jan 01 00:00:02 1970 +0000
923 | | date: Thu Jan 01 00:00:02 1970 +0000
924 | | summary: (2) collapse
924 | | summary: (2) collapse
925 | |
925 | |
926 o | changeset: 1:6db2ef61d156
926 o | changeset: 1:6db2ef61d156
927 |/ user: test
927 |/ user: test
928 | date: Thu Jan 01 00:00:01 1970 +0000
928 | date: Thu Jan 01 00:00:01 1970 +0000
929 | summary: (1) collapse
929 | summary: (1) collapse
930 |
930 |
931 o changeset: 0:e6eb3150255d
931 o changeset: 0:e6eb3150255d
932 user: test
932 user: test
933 date: Thu Jan 01 00:00:00 1970 +0000
933 date: Thu Jan 01 00:00:00 1970 +0000
934 summary: (0) root
934 summary: (0) root
935
935
936
936
937
937
938 File glog per revset (only merges):
938 File glog per revset (only merges):
939
939
940 $ hg log -G -r 'file("a")' -m
940 $ hg log -G -r 'file("a")' -m
941 o changeset: 32:d06dffa21a31
941 o changeset: 32:d06dffa21a31
942 |\ parent: 27:886ed638191b
942 |\ parent: 27:886ed638191b
943 | | parent: 31:621d83e11f67
943 | | parent: 31:621d83e11f67
944 | | user: test
944 | | user: test
945 | | date: Thu Jan 01 00:00:32 1970 +0000
945 | | date: Thu Jan 01 00:00:32 1970 +0000
946 | | summary: (32) expand
946 | | summary: (32) expand
947 | |
947 | |
948 o | changeset: 31:621d83e11f67
948 o | changeset: 31:621d83e11f67
949 |\| parent: 21:d42a756af44d
949 |\| parent: 21:d42a756af44d
950 | | parent: 30:6e11cd4b648f
950 | | parent: 30:6e11cd4b648f
951 | | user: test
951 | | user: test
952 | | date: Thu Jan 01 00:00:31 1970 +0000
952 | | date: Thu Jan 01 00:00:31 1970 +0000
953 | | summary: (31) expand
953 | | summary: (31) expand
954 | |
954 | |
955 o | changeset: 30:6e11cd4b648f
955 o | changeset: 30:6e11cd4b648f
956 |\ \ parent: 28:44ecd0b9ae99
956 |\ \ parent: 28:44ecd0b9ae99
957 | | | parent: 29:cd9bb2be7593
957 | | | parent: 29:cd9bb2be7593
958 | | | user: test
958 | | | user: test
959 | | | date: Thu Jan 01 00:00:30 1970 +0000
959 | | | date: Thu Jan 01 00:00:30 1970 +0000
960 | | | summary: (30) expand
960 | | | summary: (30) expand
961 | | |
961 | | |
962 o | | changeset: 28:44ecd0b9ae99
962 o | | changeset: 28:44ecd0b9ae99
963 |\ \ \ parent: 1:6db2ef61d156
963 |\ \ \ parent: 1:6db2ef61d156
964 | | | | parent: 26:7f25b6c2f0b9
964 | | | | parent: 26:7f25b6c2f0b9
965 | | | | user: test
965 | | | | user: test
966 | | | | date: Thu Jan 01 00:00:28 1970 +0000
966 | | | | date: Thu Jan 01 00:00:28 1970 +0000
967 | | | | summary: (28) merge zero known
967 | | | | summary: (28) merge zero known
968 | | | |
968 | | | |
969 o | | | changeset: 26:7f25b6c2f0b9
969 o | | | changeset: 26:7f25b6c2f0b9
970 |\ \ \ \ parent: 18:1aa84d96232a
970 |\ \ \ \ parent: 18:1aa84d96232a
971 | | | | | parent: 25:91da8ed57247
971 | | | | | parent: 25:91da8ed57247
972 | | | | | user: test
972 | | | | | user: test
973 | | | | | date: Thu Jan 01 00:00:26 1970 +0000
973 | | | | | date: Thu Jan 01 00:00:26 1970 +0000
974 | | | | | summary: (26) merge one known; far right
974 | | | | | summary: (26) merge one known; far right
975 | | | | |
975 | | | | |
976 | o-----+ changeset: 25:91da8ed57247
976 | o-----+ changeset: 25:91da8ed57247
977 | | | | | parent: 21:d42a756af44d
977 | | | | | parent: 21:d42a756af44d
978 | | | | | parent: 24:a9c19a3d96b7
978 | | | | | parent: 24:a9c19a3d96b7
979 | | | | | user: test
979 | | | | | user: test
980 | | | | | date: Thu Jan 01 00:00:25 1970 +0000
980 | | | | | date: Thu Jan 01 00:00:25 1970 +0000
981 | | | | | summary: (25) merge one known; far left
981 | | | | | summary: (25) merge one known; far left
982 | | | | |
982 | | | | |
983 | o | | | changeset: 24:a9c19a3d96b7
983 | o | | | changeset: 24:a9c19a3d96b7
984 | |\ \ \ \ parent: 0:e6eb3150255d
984 | |\ \ \ \ parent: 0:e6eb3150255d
985 | | | | | | parent: 23:a01cddf0766d
985 | | | | | | parent: 23:a01cddf0766d
986 | | | | | | user: test
986 | | | | | | user: test
987 | | | | | | date: Thu Jan 01 00:00:24 1970 +0000
987 | | | | | | date: Thu Jan 01 00:00:24 1970 +0000
988 | | | | | | summary: (24) merge one known; immediate right
988 | | | | | | summary: (24) merge one known; immediate right
989 | | | | | |
989 | | | | | |
990 | o---+ | | changeset: 23:a01cddf0766d
990 | o---+ | | changeset: 23:a01cddf0766d
991 | | | | | | parent: 1:6db2ef61d156
991 | | | | | | parent: 1:6db2ef61d156
992 | | | | | | parent: 22:e0d9cccacb5d
992 | | | | | | parent: 22:e0d9cccacb5d
993 | | | | | | user: test
993 | | | | | | user: test
994 | | | | | | date: Thu Jan 01 00:00:23 1970 +0000
994 | | | | | | date: Thu Jan 01 00:00:23 1970 +0000
995 | | | | | | summary: (23) merge one known; immediate left
995 | | | | | | summary: (23) merge one known; immediate left
996 | | | | | |
996 | | | | | |
997 | o-------+ changeset: 22:e0d9cccacb5d
997 | o-------+ changeset: 22:e0d9cccacb5d
998 | | | | | | parent: 18:1aa84d96232a
998 | | | | | | parent: 18:1aa84d96232a
999 |/ / / / / parent: 21:d42a756af44d
999 |/ / / / / parent: 21:d42a756af44d
1000 | | | | | user: test
1000 | | | | | user: test
1001 | | | | | date: Thu Jan 01 00:00:22 1970 +0000
1001 | | | | | date: Thu Jan 01 00:00:22 1970 +0000
1002 | | | | | summary: (22) merge two known; one far left, one far right
1002 | | | | | summary: (22) merge two known; one far left, one far right
1003 | | | | |
1003 | | | | |
1004 | | | | o changeset: 21:d42a756af44d
1004 | | | | o changeset: 21:d42a756af44d
1005 | | | | |\ parent: 19:31ddc2c1573b
1005 | | | | |\ parent: 19:31ddc2c1573b
1006 | | | | | | parent: 20:d30ed6450e32
1006 | | | | | | parent: 20:d30ed6450e32
1007 | | | | | | user: test
1007 | | | | | | user: test
1008 | | | | | | date: Thu Jan 01 00:00:21 1970 +0000
1008 | | | | | | date: Thu Jan 01 00:00:21 1970 +0000
1009 | | | | | | summary: (21) expand
1009 | | | | | | summary: (21) expand
1010 | | | | | |
1010 | | | | | |
1011 +-+-------o changeset: 20:d30ed6450e32
1011 +-+-------o changeset: 20:d30ed6450e32
1012 | | | | | parent: 0:e6eb3150255d
1012 | | | | | parent: 0:e6eb3150255d
1013 | | | | | parent: 18:1aa84d96232a
1013 | | | | | parent: 18:1aa84d96232a
1014 | | | | | user: test
1014 | | | | | user: test
1015 | | | | | date: Thu Jan 01 00:00:20 1970 +0000
1015 | | | | | date: Thu Jan 01 00:00:20 1970 +0000
1016 | | | | | summary: (20) merge two known; two far right
1016 | | | | | summary: (20) merge two known; two far right
1017 | | | | |
1017 | | | | |
1018 | | | | o changeset: 19:31ddc2c1573b
1018 | | | | o changeset: 19:31ddc2c1573b
1019 | | | | |\ parent: 15:1dda3f72782d
1019 | | | | |\ parent: 15:1dda3f72782d
1020 | | | | | | parent: 17:44765d7c06e0
1020 | | | | | | parent: 17:44765d7c06e0
1021 | | | | | | user: test
1021 | | | | | | user: test
1022 | | | | | | date: Thu Jan 01 00:00:19 1970 +0000
1022 | | | | | | date: Thu Jan 01 00:00:19 1970 +0000
1023 | | | | | | summary: (19) expand
1023 | | | | | | summary: (19) expand
1024 | | | | | |
1024 | | | | | |
1025 o---+---+ | changeset: 18:1aa84d96232a
1025 o---+---+ | changeset: 18:1aa84d96232a
1026 | | | | | parent: 1:6db2ef61d156
1026 | | | | | parent: 1:6db2ef61d156
1027 / / / / / parent: 15:1dda3f72782d
1027 / / / / / parent: 15:1dda3f72782d
1028 | | | | | user: test
1028 | | | | | user: test
1029 | | | | | date: Thu Jan 01 00:00:18 1970 +0000
1029 | | | | | date: Thu Jan 01 00:00:18 1970 +0000
1030 | | | | | summary: (18) merge two known; two far left
1030 | | | | | summary: (18) merge two known; two far left
1031 | | | | |
1031 | | | | |
1032 | | | | o changeset: 17:44765d7c06e0
1032 | | | | o changeset: 17:44765d7c06e0
1033 | | | | |\ parent: 12:86b91144a6e9
1033 | | | | |\ parent: 12:86b91144a6e9
1034 | | | | | | parent: 16:3677d192927d
1034 | | | | | | parent: 16:3677d192927d
1035 | | | | | | user: test
1035 | | | | | | user: test
1036 | | | | | | date: Thu Jan 01 00:00:17 1970 +0000
1036 | | | | | | date: Thu Jan 01 00:00:17 1970 +0000
1037 | | | | | | summary: (17) expand
1037 | | | | | | summary: (17) expand
1038 | | | | | |
1038 | | | | | |
1039 +-+-------o changeset: 16:3677d192927d
1039 +-+-------o changeset: 16:3677d192927d
1040 | | | | | parent: 0:e6eb3150255d
1040 | | | | | parent: 0:e6eb3150255d
1041 | | | | | parent: 1:6db2ef61d156
1041 | | | | | parent: 1:6db2ef61d156
1042 | | | | | user: test
1042 | | | | | user: test
1043 | | | | | date: Thu Jan 01 00:00:16 1970 +0000
1043 | | | | | date: Thu Jan 01 00:00:16 1970 +0000
1044 | | | | | summary: (16) merge two known; one immediate right, one near right
1044 | | | | | summary: (16) merge two known; one immediate right, one near right
1045 | | | | |
1045 | | | | |
1046 | | | o | changeset: 15:1dda3f72782d
1046 | | | o | changeset: 15:1dda3f72782d
1047 | | | |\ \ parent: 13:22d8966a97e3
1047 | | | |\ \ parent: 13:22d8966a97e3
1048 | | | | | | parent: 14:8eac370358ef
1048 | | | | | | parent: 14:8eac370358ef
1049 | | | | | | user: test
1049 | | | | | | user: test
1050 | | | | | | date: Thu Jan 01 00:00:15 1970 +0000
1050 | | | | | | date: Thu Jan 01 00:00:15 1970 +0000
1051 | | | | | | summary: (15) expand
1051 | | | | | | summary: (15) expand
1052 | | | | | |
1052 | | | | | |
1053 +-------o | changeset: 14:8eac370358ef
1053 +-------o | changeset: 14:8eac370358ef
1054 | | | | |/ parent: 0:e6eb3150255d
1054 | | | | |/ parent: 0:e6eb3150255d
1055 | | | | | parent: 12:86b91144a6e9
1055 | | | | | parent: 12:86b91144a6e9
1056 | | | | | user: test
1056 | | | | | user: test
1057 | | | | | date: Thu Jan 01 00:00:14 1970 +0000
1057 | | | | | date: Thu Jan 01 00:00:14 1970 +0000
1058 | | | | | summary: (14) merge two known; one immediate right, one far right
1058 | | | | | summary: (14) merge two known; one immediate right, one far right
1059 | | | | |
1059 | | | | |
1060 | | | o | changeset: 13:22d8966a97e3
1060 | | | o | changeset: 13:22d8966a97e3
1061 | | | |\ \ parent: 9:7010c0af0a35
1061 | | | |\ \ parent: 9:7010c0af0a35
1062 | | | | | | parent: 11:832d76e6bdf2
1062 | | | | | | parent: 11:832d76e6bdf2
1063 | | | | | | user: test
1063 | | | | | | user: test
1064 | | | | | | date: Thu Jan 01 00:00:13 1970 +0000
1064 | | | | | | date: Thu Jan 01 00:00:13 1970 +0000
1065 | | | | | | summary: (13) expand
1065 | | | | | | summary: (13) expand
1066 | | | | | |
1066 | | | | | |
1067 | +---+---o changeset: 12:86b91144a6e9
1067 | +---+---o changeset: 12:86b91144a6e9
1068 | | | | | parent: 1:6db2ef61d156
1068 | | | | | parent: 1:6db2ef61d156
1069 | | | | | parent: 9:7010c0af0a35
1069 | | | | | parent: 9:7010c0af0a35
1070 | | | | | user: test
1070 | | | | | user: test
1071 | | | | | date: Thu Jan 01 00:00:12 1970 +0000
1071 | | | | | date: Thu Jan 01 00:00:12 1970 +0000
1072 | | | | | summary: (12) merge two known; one immediate right, one far left
1072 | | | | | summary: (12) merge two known; one immediate right, one far left
1073 | | | | |
1073 | | | | |
1074 | | | | o changeset: 11:832d76e6bdf2
1074 | | | | o changeset: 11:832d76e6bdf2
1075 | | | | |\ parent: 6:b105a072e251
1075 | | | | |\ parent: 6:b105a072e251
1076 | | | | | | parent: 10:74c64d036d72
1076 | | | | | | parent: 10:74c64d036d72
1077 | | | | | | user: test
1077 | | | | | | user: test
1078 | | | | | | date: Thu Jan 01 00:00:11 1970 +0000
1078 | | | | | | date: Thu Jan 01 00:00:11 1970 +0000
1079 | | | | | | summary: (11) expand
1079 | | | | | | summary: (11) expand
1080 | | | | | |
1080 | | | | | |
1081 +---------o changeset: 10:74c64d036d72
1081 +---------o changeset: 10:74c64d036d72
1082 | | | | |/ parent: 0:e6eb3150255d
1082 | | | | |/ parent: 0:e6eb3150255d
1083 | | | | | parent: 6:b105a072e251
1083 | | | | | parent: 6:b105a072e251
1084 | | | | | user: test
1084 | | | | | user: test
1085 | | | | | date: Thu Jan 01 00:00:10 1970 +0000
1085 | | | | | date: Thu Jan 01 00:00:10 1970 +0000
1086 | | | | | summary: (10) merge two known; one immediate left, one near right
1086 | | | | | summary: (10) merge two known; one immediate left, one near right
1087 | | | | |
1087 | | | | |
1088 | | | o | changeset: 9:7010c0af0a35
1088 | | | o | changeset: 9:7010c0af0a35
1089 | | | |\ \ parent: 7:b632bb1b1224
1089 | | | |\ \ parent: 7:b632bb1b1224
1090 | | | | | | parent: 8:7a0b11f71937
1090 | | | | | | parent: 8:7a0b11f71937
1091 | | | | | | user: test
1091 | | | | | | user: test
1092 | | | | | | date: Thu Jan 01 00:00:09 1970 +0000
1092 | | | | | | date: Thu Jan 01 00:00:09 1970 +0000
1093 | | | | | | summary: (9) expand
1093 | | | | | | summary: (9) expand
1094 | | | | | |
1094 | | | | | |
1095 +-------o | changeset: 8:7a0b11f71937
1095 +-------o | changeset: 8:7a0b11f71937
1096 | | | |/ / parent: 0:e6eb3150255d
1096 | | | |/ / parent: 0:e6eb3150255d
1097 | | | | | parent: 7:b632bb1b1224
1097 | | | | | parent: 7:b632bb1b1224
1098 | | | | | user: test
1098 | | | | | user: test
1099 | | | | | date: Thu Jan 01 00:00:08 1970 +0000
1099 | | | | | date: Thu Jan 01 00:00:08 1970 +0000
1100 | | | | | summary: (8) merge two known; one immediate left, one far right
1100 | | | | | summary: (8) merge two known; one immediate left, one far right
1101 | | | | |
1101 | | | | |
1102 | | | o | changeset: 7:b632bb1b1224
1102 | | | o | changeset: 7:b632bb1b1224
1103 | | | |\ \ parent: 2:3d9a33b8d1e1
1103 | | | |\ \ parent: 2:3d9a33b8d1e1
1104 | | | | | | parent: 5:4409d547b708
1104 | | | | | | parent: 5:4409d547b708
1105 | | | | | | user: test
1105 | | | | | | user: test
1106 | | | | | | date: Thu Jan 01 00:00:07 1970 +0000
1106 | | | | | | date: Thu Jan 01 00:00:07 1970 +0000
1107 | | | | | | summary: (7) expand
1107 | | | | | | summary: (7) expand
1108 | | | | | |
1108 | | | | | |
1109 | | | +---o changeset: 6:b105a072e251
1109 | | | +---o changeset: 6:b105a072e251
1110 | | | | |/ parent: 2:3d9a33b8d1e1
1110 | | | | |/ parent: 2:3d9a33b8d1e1
1111 | | | | | parent: 5:4409d547b708
1111 | | | | | parent: 5:4409d547b708
1112 | | | | | user: test
1112 | | | | | user: test
1113 | | | | | date: Thu Jan 01 00:00:06 1970 +0000
1113 | | | | | date: Thu Jan 01 00:00:06 1970 +0000
1114 | | | | | summary: (6) merge two known; one immediate left, one far left
1114 | | | | | summary: (6) merge two known; one immediate left, one far left
1115 | | | | |
1115 | | | | |
1116 | | | o | changeset: 5:4409d547b708
1116 | | | o | changeset: 5:4409d547b708
1117 | | | |\ \ parent: 3:27eef8ed80b4
1117 | | | |\ \ parent: 3:27eef8ed80b4
1118 | | | | | | parent: 4:26a8bac39d9f
1118 | | | | | | parent: 4:26a8bac39d9f
1119 | | | | | | user: test
1119 | | | | | | user: test
1120 | | | | | | date: Thu Jan 01 00:00:05 1970 +0000
1120 | | | | | | date: Thu Jan 01 00:00:05 1970 +0000
1121 | | | | | | summary: (5) expand
1121 | | | | | | summary: (5) expand
1122 | | | | | |
1122 | | | | | |
1123 | +---o | | changeset: 4:26a8bac39d9f
1123 | +---o | | changeset: 4:26a8bac39d9f
1124 | | | |/ / parent: 1:6db2ef61d156
1124 | | | |/ / parent: 1:6db2ef61d156
1125 | | | | | parent: 3:27eef8ed80b4
1125 | | | | | parent: 3:27eef8ed80b4
1126 | | | | | user: test
1126 | | | | | user: test
1127 | | | | | date: Thu Jan 01 00:00:04 1970 +0000
1127 | | | | | date: Thu Jan 01 00:00:04 1970 +0000
1128 | | | | | summary: (4) merge two known; one immediate left, one immediate right
1128 | | | | | summary: (4) merge two known; one immediate left, one immediate right
1129 | | | | |
1129 | | | | |
1130
1130
1131
1131
1132 Empty revision range - display nothing:
1132 Empty revision range - display nothing:
1133 $ hg log -G -r 1..0
1133 $ hg log -G -r 1..0
1134
1134
1135 $ cd ..
1135 $ cd ..
1136
1136
1137 #if no-outer-repo
1137 #if no-outer-repo
1138
1138
1139 From outer space:
1139 From outer space:
1140 $ hg log -G -l1 repo
1140 $ hg log -G -l1 repo
1141 @ changeset: 34:fea3ac5810e0
1141 @ changeset: 34:fea3ac5810e0
1142 | tag: tip
1142 | tag: tip
1143 | parent: 32:d06dffa21a31
1143 | parent: 32:d06dffa21a31
1144 | user: test
1144 | user: test
1145 | date: Thu Jan 01 00:00:34 1970 +0000
1145 | date: Thu Jan 01 00:00:34 1970 +0000
1146 | summary: (34) head
1146 | summary: (34) head
1147 |
1147 |
1148 $ hg log -G -l1 repo/a
1148 $ hg log -G -l1 repo/a
1149 @ changeset: 34:fea3ac5810e0
1149 @ changeset: 34:fea3ac5810e0
1150 | tag: tip
1150 | tag: tip
1151 | parent: 32:d06dffa21a31
1151 | parent: 32:d06dffa21a31
1152 | user: test
1152 | user: test
1153 | date: Thu Jan 01 00:00:34 1970 +0000
1153 | date: Thu Jan 01 00:00:34 1970 +0000
1154 | summary: (34) head
1154 | summary: (34) head
1155 |
1155 |
1156 $ hg log -G -l1 repo/missing
1156 $ hg log -G -l1 repo/missing
1157
1157
1158 #endif
1158 #endif
1159
1159
1160 File log with revs != cset revs:
1160 File log with revs != cset revs:
1161 $ hg init flog
1161 $ hg init flog
1162 $ cd flog
1162 $ cd flog
1163 $ echo one >one
1163 $ echo one >one
1164 $ hg add one
1164 $ hg add one
1165 $ hg commit -mone
1165 $ hg commit -mone
1166 $ echo two >two
1166 $ echo two >two
1167 $ hg add two
1167 $ hg add two
1168 $ hg commit -mtwo
1168 $ hg commit -mtwo
1169 $ echo more >two
1169 $ echo more >two
1170 $ hg commit -mmore
1170 $ hg commit -mmore
1171 $ hg log -G two
1171 $ hg log -G two
1172 @ changeset: 2:12c28321755b
1172 @ changeset: 2:12c28321755b
1173 | tag: tip
1173 | tag: tip
1174 | user: test
1174 | user: test
1175 | date: Thu Jan 01 00:00:00 1970 +0000
1175 | date: Thu Jan 01 00:00:00 1970 +0000
1176 | summary: more
1176 | summary: more
1177 |
1177 |
1178 o changeset: 1:5ac72c0599bf
1178 o changeset: 1:5ac72c0599bf
1179 | user: test
1179 | user: test
1180 | date: Thu Jan 01 00:00:00 1970 +0000
1180 | date: Thu Jan 01 00:00:00 1970 +0000
1181 | summary: two
1181 | summary: two
1182 |
1182 |
1183
1183
1184 Issue1896: File log with explicit style
1184 Issue1896: File log with explicit style
1185 $ hg log -G --style=default one
1185 $ hg log -G --style=default one
1186 o changeset: 0:3d578b4a1f53
1186 o changeset: 0:3d578b4a1f53
1187 user: test
1187 user: test
1188 date: Thu Jan 01 00:00:00 1970 +0000
1188 date: Thu Jan 01 00:00:00 1970 +0000
1189 summary: one
1189 summary: one
1190
1190
1191 Issue2395: glog --style header and footer
1191 Issue2395: glog --style header and footer
1192 $ hg log -G --style=xml one
1192 $ hg log -G --style=xml one
1193 <?xml version="1.0"?>
1193 <?xml version="1.0"?>
1194 <log>
1194 <log>
1195 o <logentry revision="0" node="3d578b4a1f537d5fcf7301bfa9c0b97adfaa6fb1">
1195 o <logentry revision="0" node="3d578b4a1f537d5fcf7301bfa9c0b97adfaa6fb1">
1196 <author email="test">test</author>
1196 <author email="test">test</author>
1197 <date>1970-01-01T00:00:00+00:00</date>
1197 <date>1970-01-01T00:00:00+00:00</date>
1198 <msg xml:space="preserve">one</msg>
1198 <msg xml:space="preserve">one</msg>
1199 </logentry>
1199 </logentry>
1200 </log>
1200 </log>
1201
1201
1202 $ cd ..
1202 $ cd ..
1203
1203
1204 Incoming and outgoing:
1204 Incoming and outgoing:
1205
1205
1206 $ hg clone -U -r31 repo repo2
1206 $ hg clone -U -r31 repo repo2
1207 adding changesets
1207 adding changesets
1208 adding manifests
1208 adding manifests
1209 adding file changes
1209 adding file changes
1210 added 31 changesets with 31 changes to 1 files
1210 added 31 changesets with 31 changes to 1 files
1211 $ cd repo2
1211 $ cd repo2
1212
1212
1213 $ hg incoming --graph ../repo
1213 $ hg incoming --graph ../repo
1214 comparing with ../repo
1214 comparing with ../repo
1215 searching for changes
1215 searching for changes
1216 o changeset: 34:fea3ac5810e0
1216 o changeset: 34:fea3ac5810e0
1217 | tag: tip
1217 | tag: tip
1218 | parent: 32:d06dffa21a31
1218 | parent: 32:d06dffa21a31
1219 | user: test
1219 | user: test
1220 | date: Thu Jan 01 00:00:34 1970 +0000
1220 | date: Thu Jan 01 00:00:34 1970 +0000
1221 | summary: (34) head
1221 | summary: (34) head
1222 |
1222 |
1223 | o changeset: 33:68608f5145f9
1223 | o changeset: 33:68608f5145f9
1224 | parent: 18:1aa84d96232a
1224 | parent: 18:1aa84d96232a
1225 | user: test
1225 | user: test
1226 | date: Thu Jan 01 00:00:33 1970 +0000
1226 | date: Thu Jan 01 00:00:33 1970 +0000
1227 | summary: (33) head
1227 | summary: (33) head
1228 |
1228 |
1229 o changeset: 32:d06dffa21a31
1229 o changeset: 32:d06dffa21a31
1230 | parent: 27:886ed638191b
1230 | parent: 27:886ed638191b
1231 | parent: 31:621d83e11f67
1231 | parent: 31:621d83e11f67
1232 | user: test
1232 | user: test
1233 | date: Thu Jan 01 00:00:32 1970 +0000
1233 | date: Thu Jan 01 00:00:32 1970 +0000
1234 | summary: (32) expand
1234 | summary: (32) expand
1235 |
1235 |
1236 o changeset: 27:886ed638191b
1236 o changeset: 27:886ed638191b
1237 parent: 21:d42a756af44d
1237 parent: 21:d42a756af44d
1238 user: test
1238 user: test
1239 date: Thu Jan 01 00:00:27 1970 +0000
1239 date: Thu Jan 01 00:00:27 1970 +0000
1240 summary: (27) collapse
1240 summary: (27) collapse
1241
1241
1242 $ cd ..
1242 $ cd ..
1243
1243
1244 $ hg -R repo outgoing --graph repo2
1244 $ hg -R repo outgoing --graph repo2
1245 comparing with repo2
1245 comparing with repo2
1246 searching for changes
1246 searching for changes
1247 @ changeset: 34:fea3ac5810e0
1247 @ changeset: 34:fea3ac5810e0
1248 | tag: tip
1248 | tag: tip
1249 | parent: 32:d06dffa21a31
1249 | parent: 32:d06dffa21a31
1250 | user: test
1250 | user: test
1251 | date: Thu Jan 01 00:00:34 1970 +0000
1251 | date: Thu Jan 01 00:00:34 1970 +0000
1252 | summary: (34) head
1252 | summary: (34) head
1253 |
1253 |
1254 | o changeset: 33:68608f5145f9
1254 | o changeset: 33:68608f5145f9
1255 | parent: 18:1aa84d96232a
1255 | parent: 18:1aa84d96232a
1256 | user: test
1256 | user: test
1257 | date: Thu Jan 01 00:00:33 1970 +0000
1257 | date: Thu Jan 01 00:00:33 1970 +0000
1258 | summary: (33) head
1258 | summary: (33) head
1259 |
1259 |
1260 o changeset: 32:d06dffa21a31
1260 o changeset: 32:d06dffa21a31
1261 | parent: 27:886ed638191b
1261 | parent: 27:886ed638191b
1262 | parent: 31:621d83e11f67
1262 | parent: 31:621d83e11f67
1263 | user: test
1263 | user: test
1264 | date: Thu Jan 01 00:00:32 1970 +0000
1264 | date: Thu Jan 01 00:00:32 1970 +0000
1265 | summary: (32) expand
1265 | summary: (32) expand
1266 |
1266 |
1267 o changeset: 27:886ed638191b
1267 o changeset: 27:886ed638191b
1268 parent: 21:d42a756af44d
1268 parent: 21:d42a756af44d
1269 user: test
1269 user: test
1270 date: Thu Jan 01 00:00:27 1970 +0000
1270 date: Thu Jan 01 00:00:27 1970 +0000
1271 summary: (27) collapse
1271 summary: (27) collapse
1272
1272
1273
1273
1274 File + limit with revs != cset revs:
1274 File + limit with revs != cset revs:
1275 $ cd repo
1275 $ cd repo
1276 $ touch b
1276 $ touch b
1277 $ hg ci -Aqm0
1277 $ hg ci -Aqm0
1278 $ hg log -G -l2 a
1278 $ hg log -G -l2 a
1279 o changeset: 34:fea3ac5810e0
1279 o changeset: 34:fea3ac5810e0
1280 | parent: 32:d06dffa21a31
1280 | parent: 32:d06dffa21a31
1281 | user: test
1281 | user: test
1282 | date: Thu Jan 01 00:00:34 1970 +0000
1282 | date: Thu Jan 01 00:00:34 1970 +0000
1283 | summary: (34) head
1283 | summary: (34) head
1284 |
1284 |
1285 | o changeset: 33:68608f5145f9
1285 | o changeset: 33:68608f5145f9
1286 | | parent: 18:1aa84d96232a
1286 | | parent: 18:1aa84d96232a
1287 | | user: test
1287 | | user: test
1288 | | date: Thu Jan 01 00:00:33 1970 +0000
1288 | | date: Thu Jan 01 00:00:33 1970 +0000
1289 | | summary: (33) head
1289 | | summary: (33) head
1290 | |
1290 | |
1291
1291
1292 File + limit + -ra:b, (b - a) < limit:
1292 File + limit + -ra:b, (b - a) < limit:
1293 $ hg log -G -l3000 -r32:tip a
1293 $ hg log -G -l3000 -r32:tip a
1294 o changeset: 34:fea3ac5810e0
1294 o changeset: 34:fea3ac5810e0
1295 | parent: 32:d06dffa21a31
1295 | parent: 32:d06dffa21a31
1296 | user: test
1296 | user: test
1297 | date: Thu Jan 01 00:00:34 1970 +0000
1297 | date: Thu Jan 01 00:00:34 1970 +0000
1298 | summary: (34) head
1298 | summary: (34) head
1299 |
1299 |
1300 | o changeset: 33:68608f5145f9
1300 | o changeset: 33:68608f5145f9
1301 | | parent: 18:1aa84d96232a
1301 | | parent: 18:1aa84d96232a
1302 | | user: test
1302 | | user: test
1303 | | date: Thu Jan 01 00:00:33 1970 +0000
1303 | | date: Thu Jan 01 00:00:33 1970 +0000
1304 | | summary: (33) head
1304 | | summary: (33) head
1305 | |
1305 | |
1306 o | changeset: 32:d06dffa21a31
1306 o | changeset: 32:d06dffa21a31
1307 |\ \ parent: 27:886ed638191b
1307 |\ \ parent: 27:886ed638191b
1308 | | | parent: 31:621d83e11f67
1308 | | | parent: 31:621d83e11f67
1309 | | | user: test
1309 | | | user: test
1310 | | | date: Thu Jan 01 00:00:32 1970 +0000
1310 | | | date: Thu Jan 01 00:00:32 1970 +0000
1311 | | | summary: (32) expand
1311 | | | summary: (32) expand
1312 | | |
1312 | | |
1313
1313
1314 Point out a common and an uncommon unshown parent
1314 Point out a common and an uncommon unshown parent
1315
1315
1316 $ hg log -G -r 'rev(8) or rev(9)'
1316 $ hg log -G -r 'rev(8) or rev(9)'
1317 o changeset: 9:7010c0af0a35
1317 o changeset: 9:7010c0af0a35
1318 |\ parent: 7:b632bb1b1224
1318 |\ parent: 7:b632bb1b1224
1319 | | parent: 8:7a0b11f71937
1319 | | parent: 8:7a0b11f71937
1320 | | user: test
1320 | | user: test
1321 | | date: Thu Jan 01 00:00:09 1970 +0000
1321 | | date: Thu Jan 01 00:00:09 1970 +0000
1322 | | summary: (9) expand
1322 | | summary: (9) expand
1323 | |
1323 | |
1324 o | changeset: 8:7a0b11f71937
1324 o | changeset: 8:7a0b11f71937
1325 |\| parent: 0:e6eb3150255d
1325 |\| parent: 0:e6eb3150255d
1326 | | parent: 7:b632bb1b1224
1326 | | parent: 7:b632bb1b1224
1327 | | user: test
1327 | | user: test
1328 | | date: Thu Jan 01 00:00:08 1970 +0000
1328 | | date: Thu Jan 01 00:00:08 1970 +0000
1329 | | summary: (8) merge two known; one immediate left, one far right
1329 | | summary: (8) merge two known; one immediate left, one far right
1330 | |
1330 | |
1331
1331
1332 File + limit + -ra:b, b < tip:
1332 File + limit + -ra:b, b < tip:
1333
1333
1334 $ hg log -G -l1 -r32:34 a
1334 $ hg log -G -l1 -r32:34 a
1335 o changeset: 34:fea3ac5810e0
1335 o changeset: 34:fea3ac5810e0
1336 | parent: 32:d06dffa21a31
1336 | parent: 32:d06dffa21a31
1337 | user: test
1337 | user: test
1338 | date: Thu Jan 01 00:00:34 1970 +0000
1338 | date: Thu Jan 01 00:00:34 1970 +0000
1339 | summary: (34) head
1339 | summary: (34) head
1340 |
1340 |
1341
1341
1342 file(File) + limit + -ra:b, b < tip:
1342 file(File) + limit + -ra:b, b < tip:
1343
1343
1344 $ hg log -G -l1 -r32:34 -r 'file("a")'
1344 $ hg log -G -l1 -r32:34 -r 'file("a")'
1345 o changeset: 34:fea3ac5810e0
1345 o changeset: 34:fea3ac5810e0
1346 | parent: 32:d06dffa21a31
1346 | parent: 32:d06dffa21a31
1347 | user: test
1347 | user: test
1348 | date: Thu Jan 01 00:00:34 1970 +0000
1348 | date: Thu Jan 01 00:00:34 1970 +0000
1349 | summary: (34) head
1349 | summary: (34) head
1350 |
1350 |
1351
1351
1352 limit(file(File) and a::b), b < tip:
1352 limit(file(File) and a::b), b < tip:
1353
1353
1354 $ hg log -G -r 'limit(file("a") and 32::34, 1)'
1354 $ hg log -G -r 'limit(file("a") and 32::34, 1)'
1355 o changeset: 32:d06dffa21a31
1355 o changeset: 32:d06dffa21a31
1356 |\ parent: 27:886ed638191b
1356 |\ parent: 27:886ed638191b
1357 | | parent: 31:621d83e11f67
1357 | | parent: 31:621d83e11f67
1358 | | user: test
1358 | | user: test
1359 | | date: Thu Jan 01 00:00:32 1970 +0000
1359 | | date: Thu Jan 01 00:00:32 1970 +0000
1360 | | summary: (32) expand
1360 | | summary: (32) expand
1361 | |
1361 | |
1362
1362
1363 File + limit + -ra:b, b < tip:
1363 File + limit + -ra:b, b < tip:
1364
1364
1365 $ hg log -G -r 'limit(file("a") and 34::32, 1)'
1365 $ hg log -G -r 'limit(file("a") and 34::32, 1)'
1366
1366
1367 File + limit + -ra:b, b < tip, (b - a) < limit:
1367 File + limit + -ra:b, b < tip, (b - a) < limit:
1368
1368
1369 $ hg log -G -l10 -r33:34 a
1369 $ hg log -G -l10 -r33:34 a
1370 o changeset: 34:fea3ac5810e0
1370 o changeset: 34:fea3ac5810e0
1371 | parent: 32:d06dffa21a31
1371 | parent: 32:d06dffa21a31
1372 | user: test
1372 | user: test
1373 | date: Thu Jan 01 00:00:34 1970 +0000
1373 | date: Thu Jan 01 00:00:34 1970 +0000
1374 | summary: (34) head
1374 | summary: (34) head
1375 |
1375 |
1376 | o changeset: 33:68608f5145f9
1376 | o changeset: 33:68608f5145f9
1377 | | parent: 18:1aa84d96232a
1377 | | parent: 18:1aa84d96232a
1378 | | user: test
1378 | | user: test
1379 | | date: Thu Jan 01 00:00:33 1970 +0000
1379 | | date: Thu Jan 01 00:00:33 1970 +0000
1380 | | summary: (33) head
1380 | | summary: (33) head
1381 | |
1381 | |
1382
1382
1383 Do not crash or produce strange graphs if history is buggy
1383 Do not crash or produce strange graphs if history is buggy
1384
1384
1385 $ hg branch branch
1385 $ hg branch branch
1386 marked working directory as branch branch
1386 marked working directory as branch branch
1387 (branches are permanent and global, did you want a bookmark?)
1387 (branches are permanent and global, did you want a bookmark?)
1388 $ commit 36 "buggy merge: identical parents" 35 35
1388 $ commit 36 "buggy merge: identical parents" 35 35
1389 $ hg log -G -l5
1389 $ hg log -G -l5
1390 @ changeset: 36:08a19a744424
1390 @ changeset: 36:08a19a744424
1391 | branch: branch
1391 | branch: branch
1392 | tag: tip
1392 | tag: tip
1393 | parent: 35:9159c3644c5e
1393 | parent: 35:9159c3644c5e
1394 | parent: 35:9159c3644c5e
1394 | parent: 35:9159c3644c5e
1395 | user: test
1395 | user: test
1396 | date: Thu Jan 01 00:00:36 1970 +0000
1396 | date: Thu Jan 01 00:00:36 1970 +0000
1397 | summary: (36) buggy merge: identical parents
1397 | summary: (36) buggy merge: identical parents
1398 |
1398 |
1399 o changeset: 35:9159c3644c5e
1399 o changeset: 35:9159c3644c5e
1400 | user: test
1400 | user: test
1401 | date: Thu Jan 01 00:00:00 1970 +0000
1401 | date: Thu Jan 01 00:00:00 1970 +0000
1402 | summary: 0
1402 | summary: 0
1403 |
1403 |
1404 o changeset: 34:fea3ac5810e0
1404 o changeset: 34:fea3ac5810e0
1405 | parent: 32:d06dffa21a31
1405 | parent: 32:d06dffa21a31
1406 | user: test
1406 | user: test
1407 | date: Thu Jan 01 00:00:34 1970 +0000
1407 | date: Thu Jan 01 00:00:34 1970 +0000
1408 | summary: (34) head
1408 | summary: (34) head
1409 |
1409 |
1410 | o changeset: 33:68608f5145f9
1410 | o changeset: 33:68608f5145f9
1411 | | parent: 18:1aa84d96232a
1411 | | parent: 18:1aa84d96232a
1412 | | user: test
1412 | | user: test
1413 | | date: Thu Jan 01 00:00:33 1970 +0000
1413 | | date: Thu Jan 01 00:00:33 1970 +0000
1414 | | summary: (33) head
1414 | | summary: (33) head
1415 | |
1415 | |
1416 o | changeset: 32:d06dffa21a31
1416 o | changeset: 32:d06dffa21a31
1417 |\ \ parent: 27:886ed638191b
1417 |\ \ parent: 27:886ed638191b
1418 | | | parent: 31:621d83e11f67
1418 | | | parent: 31:621d83e11f67
1419 | | | user: test
1419 | | | user: test
1420 | | | date: Thu Jan 01 00:00:32 1970 +0000
1420 | | | date: Thu Jan 01 00:00:32 1970 +0000
1421 | | | summary: (32) expand
1421 | | | summary: (32) expand
1422 | | |
1422 | | |
1423
1423
1424 Test log -G options
1424 Test log -G options
1425
1425
1426 $ testlog() {
1426 $ testlog() {
1427 > hg log -G --print-revset "$@"
1427 > hg log -G --print-revset "$@"
1428 > hg log --template 'nodetag {rev}\n' "$@" | grep nodetag \
1428 > hg log --template 'nodetag {rev}\n' "$@" | grep nodetag \
1429 > | sed 's/.*nodetag/nodetag/' > log.nodes
1429 > | sed 's/.*nodetag/nodetag/' > log.nodes
1430 > hg log -G --template 'nodetag {rev}\n' "$@" | grep nodetag \
1430 > hg log -G --template 'nodetag {rev}\n' "$@" | grep nodetag \
1431 > | sed 's/.*nodetag/nodetag/' > glog.nodes
1431 > | sed 's/.*nodetag/nodetag/' > glog.nodes
1432 > diff -u log.nodes glog.nodes | grep '^[-+@ ]' || :
1432 > diff -u log.nodes glog.nodes | grep '^[-+@ ]' || :
1433 > }
1433 > }
1434
1434
1435 glog always reorders nodes which explains the difference with log
1435 glog always reorders nodes which explains the difference with log
1436
1436
1437 $ testlog -r 27 -r 25 -r 21 -r 34 -r 32 -r 31
1437 $ testlog -r 27 -r 25 -r 21 -r 34 -r 32 -r 31
1438 ['27', '25', '21', '34', '32', '31']
1438 ['27', '25', '21', '34', '32', '31']
1439 []
1439 []
1440 --- log.nodes * (glob)
1440 --- log.nodes * (glob)
1441 +++ glog.nodes * (glob)
1441 +++ glog.nodes * (glob)
1442 @@ -1,6 +1,6 @@
1442 @@ -1,6 +1,6 @@
1443 -nodetag 27
1443 -nodetag 27
1444 -nodetag 25
1444 -nodetag 25
1445 -nodetag 21
1445 -nodetag 21
1446 nodetag 34
1446 nodetag 34
1447 nodetag 32
1447 nodetag 32
1448 nodetag 31
1448 nodetag 31
1449 +nodetag 27
1449 +nodetag 27
1450 +nodetag 25
1450 +nodetag 25
1451 +nodetag 21
1451 +nodetag 21
1452 $ testlog -u test -u not-a-user
1452 $ testlog -u test -u not-a-user
1453 []
1453 []
1454 (group
1454 (group
1455 (group
1455 (group
1456 (or
1456 (or
1457 (func
1457 (func
1458 ('symbol', 'user')
1458 ('symbol', 'user')
1459 ('string', 'test'))
1459 ('string', 'test'))
1460 (func
1460 (func
1461 ('symbol', 'user')
1461 ('symbol', 'user')
1462 ('string', 'not-a-user')))))
1462 ('string', 'not-a-user')))))
1463 $ testlog -b not-a-branch
1463 $ testlog -b not-a-branch
1464 abort: unknown revision 'not-a-branch'!
1464 abort: unknown revision 'not-a-branch'!
1465 abort: unknown revision 'not-a-branch'!
1465 abort: unknown revision 'not-a-branch'!
1466 abort: unknown revision 'not-a-branch'!
1466 abort: unknown revision 'not-a-branch'!
1467 $ testlog -b 35 -b 36 --only-branch branch
1467 $ testlog -b 35 -b 36 --only-branch branch
1468 []
1468 []
1469 (group
1469 (group
1470 (group
1470 (group
1471 (or
1471 (or
1472 (or
1472 (or
1473 (func
1473 (func
1474 ('symbol', 'branch')
1474 ('symbol', 'branch')
1475 ('string', 'default'))
1475 ('string', 'default'))
1476 (func
1476 (func
1477 ('symbol', 'branch')
1477 ('symbol', 'branch')
1478 ('string', 'branch')))
1478 ('string', 'branch')))
1479 (func
1479 (func
1480 ('symbol', 'branch')
1480 ('symbol', 'branch')
1481 ('string', 'branch')))))
1481 ('string', 'branch')))))
1482 $ testlog -k expand -k merge
1482 $ testlog -k expand -k merge
1483 []
1483 []
1484 (group
1484 (group
1485 (group
1485 (group
1486 (or
1486 (or
1487 (func
1487 (func
1488 ('symbol', 'keyword')
1488 ('symbol', 'keyword')
1489 ('string', 'expand'))
1489 ('string', 'expand'))
1490 (func
1490 (func
1491 ('symbol', 'keyword')
1491 ('symbol', 'keyword')
1492 ('string', 'merge')))))
1492 ('string', 'merge')))))
1493 $ testlog --only-merges
1493 $ testlog --only-merges
1494 []
1494 []
1495 (group
1495 (group
1496 (func
1496 (func
1497 ('symbol', 'merge')
1497 ('symbol', 'merge')
1498 None))
1498 None))
1499 $ testlog --no-merges
1499 $ testlog --no-merges
1500 []
1500 []
1501 (group
1501 (group
1502 (not
1502 (not
1503 (func
1503 (func
1504 ('symbol', 'merge')
1504 ('symbol', 'merge')
1505 None)))
1505 None)))
1506 $ testlog --date '2 0 to 4 0'
1506 $ testlog --date '2 0 to 4 0'
1507 []
1507 []
1508 (group
1508 (group
1509 (func
1509 (func
1510 ('symbol', 'date')
1510 ('symbol', 'date')
1511 ('string', '2 0 to 4 0')))
1511 ('string', '2 0 to 4 0')))
1512 $ hg log -G -d 'brace ) in a date'
1512 $ hg log -G -d 'brace ) in a date'
1513 abort: invalid date: 'brace ) in a date'
1513 abort: invalid date: 'brace ) in a date'
1514 [255]
1514 [255]
1515 $ testlog --prune 31 --prune 32
1515 $ testlog --prune 31 --prune 32
1516 []
1516 []
1517 (group
1517 (group
1518 (group
1518 (group
1519 (and
1519 (and
1520 (not
1520 (not
1521 (group
1521 (group
1522 (or
1522 (or
1523 ('string', '31')
1523 ('string', '31')
1524 (func
1524 (func
1525 ('symbol', 'ancestors')
1525 ('symbol', 'ancestors')
1526 ('string', '31')))))
1526 ('string', '31')))))
1527 (not
1527 (not
1528 (group
1528 (group
1529 (or
1529 (or
1530 ('string', '32')
1530 ('string', '32')
1531 (func
1531 (func
1532 ('symbol', 'ancestors')
1532 ('symbol', 'ancestors')
1533 ('string', '32'))))))))
1533 ('string', '32'))))))))
1534
1534
1535 Dedicated repo for --follow and paths filtering. The g is crafted to
1535 Dedicated repo for --follow and paths filtering. The g is crafted to
1536 have 2 filelog topological heads in a linear changeset graph.
1536 have 2 filelog topological heads in a linear changeset graph.
1537
1537
1538 $ cd ..
1538 $ cd ..
1539 $ hg init follow
1539 $ hg init follow
1540 $ cd follow
1540 $ cd follow
1541 $ testlog --follow
1541 $ testlog --follow
1542 []
1542 []
1543 []
1543 []
1544 $ echo a > a
1544 $ echo a > a
1545 $ echo aa > aa
1545 $ echo aa > aa
1546 $ echo f > f
1546 $ echo f > f
1547 $ hg ci -Am "add a" a aa f
1547 $ hg ci -Am "add a" a aa f
1548 $ hg cp a b
1548 $ hg cp a b
1549 $ hg cp f g
1549 $ hg cp f g
1550 $ hg ci -m "copy a b"
1550 $ hg ci -m "copy a b"
1551 $ mkdir dir
1551 $ mkdir dir
1552 $ hg mv b dir
1552 $ hg mv b dir
1553 $ echo g >> g
1553 $ echo g >> g
1554 $ echo f >> f
1554 $ echo f >> f
1555 $ hg ci -m "mv b dir/b"
1555 $ hg ci -m "mv b dir/b"
1556 $ hg mv a b
1556 $ hg mv a b
1557 $ hg cp -f f g
1557 $ hg cp -f f g
1558 $ echo a > d
1558 $ echo a > d
1559 $ hg add d
1559 $ hg add d
1560 $ hg ci -m "mv a b; add d"
1560 $ hg ci -m "mv a b; add d"
1561 $ hg mv dir/b e
1561 $ hg mv dir/b e
1562 $ hg ci -m "mv dir/b e"
1562 $ hg ci -m "mv dir/b e"
1563 $ hg log -G --template '({rev}) {desc|firstline}\n'
1563 $ hg log -G --template '({rev}) {desc|firstline}\n'
1564 @ (4) mv dir/b e
1564 @ (4) mv dir/b e
1565 |
1565 |
1566 o (3) mv a b; add d
1566 o (3) mv a b; add d
1567 |
1567 |
1568 o (2) mv b dir/b
1568 o (2) mv b dir/b
1569 |
1569 |
1570 o (1) copy a b
1570 o (1) copy a b
1571 |
1571 |
1572 o (0) add a
1572 o (0) add a
1573
1573
1574
1574
1575 $ testlog a
1575 $ testlog a
1576 []
1576 []
1577 (group
1577 (group
1578 (group
1578 (group
1579 (func
1579 (func
1580 ('symbol', 'filelog')
1580 ('symbol', 'filelog')
1581 ('string', 'a'))))
1581 ('string', 'a'))))
1582 $ testlog a b
1582 $ testlog a b
1583 []
1583 []
1584 (group
1584 (group
1585 (group
1585 (group
1586 (or
1586 (or
1587 (func
1587 (func
1588 ('symbol', 'filelog')
1588 ('symbol', 'filelog')
1589 ('string', 'a'))
1589 ('string', 'a'))
1590 (func
1590 (func
1591 ('symbol', 'filelog')
1591 ('symbol', 'filelog')
1592 ('string', 'b')))))
1592 ('string', 'b')))))
1593
1593
1594 Test falling back to slow path for non-existing files
1594 Test falling back to slow path for non-existing files
1595
1595
1596 $ testlog a c
1596 $ testlog a c
1597 []
1597 []
1598 (group
1598 (group
1599 (func
1599 (func
1600 ('symbol', '_matchfiles')
1600 ('symbol', '_matchfiles')
1601 (list
1601 (list
1602 (list
1602 (list
1603 (list
1603 (list
1604 ('string', 'r:')
1604 ('string', 'r:')
1605 ('string', 'd:relpath'))
1605 ('string', 'd:relpath'))
1606 ('string', 'p:a'))
1606 ('string', 'p:a'))
1607 ('string', 'p:c'))))
1607 ('string', 'p:c'))))
1608
1608
1609 Test multiple --include/--exclude/paths
1609 Test multiple --include/--exclude/paths
1610
1610
1611 $ testlog --include a --include e --exclude b --exclude e a e
1611 $ testlog --include a --include e --exclude b --exclude e a e
1612 []
1612 []
1613 (group
1613 (group
1614 (func
1614 (func
1615 ('symbol', '_matchfiles')
1615 ('symbol', '_matchfiles')
1616 (list
1616 (list
1617 (list
1617 (list
1618 (list
1618 (list
1619 (list
1619 (list
1620 (list
1620 (list
1621 (list
1621 (list
1622 (list
1622 (list
1623 ('string', 'r:')
1623 ('string', 'r:')
1624 ('string', 'd:relpath'))
1624 ('string', 'd:relpath'))
1625 ('string', 'p:a'))
1625 ('string', 'p:a'))
1626 ('string', 'p:e'))
1626 ('string', 'p:e'))
1627 ('string', 'i:a'))
1627 ('string', 'i:a'))
1628 ('string', 'i:e'))
1628 ('string', 'i:e'))
1629 ('string', 'x:b'))
1629 ('string', 'x:b'))
1630 ('string', 'x:e'))))
1630 ('string', 'x:e'))))
1631
1631
1632 Test glob expansion of pats
1632 Test glob expansion of pats
1633
1633
1634 $ expandglobs=`python -c "import mercurial.util; \
1634 $ expandglobs=`python -c "import mercurial.util; \
1635 > print mercurial.util.expandglobs and 'true' or 'false'"`
1635 > print mercurial.util.expandglobs and 'true' or 'false'"`
1636 $ if [ $expandglobs = "true" ]; then
1636 $ if [ $expandglobs = "true" ]; then
1637 > testlog 'a*';
1637 > testlog 'a*';
1638 > else
1638 > else
1639 > testlog a*;
1639 > testlog a*;
1640 > fi;
1640 > fi;
1641 []
1641 []
1642 (group
1642 (group
1643 (group
1643 (group
1644 (func
1644 (func
1645 ('symbol', 'filelog')
1645 ('symbol', 'filelog')
1646 ('string', 'aa'))))
1646 ('string', 'aa'))))
1647
1647
1648 Test --follow on a directory
1648 Test --follow on a directory
1649
1649
1650 $ testlog -f dir
1650 $ testlog -f dir
1651 abort: cannot follow file not in parent revision: "dir"
1651 abort: cannot follow file not in parent revision: "dir"
1652 abort: cannot follow file not in parent revision: "dir"
1652 abort: cannot follow file not in parent revision: "dir"
1653 abort: cannot follow file not in parent revision: "dir"
1653 abort: cannot follow file not in parent revision: "dir"
1654
1654
1655 Test --follow on file not in parent revision
1655 Test --follow on file not in parent revision
1656
1656
1657 $ testlog -f a
1657 $ testlog -f a
1658 abort: cannot follow file not in parent revision: "a"
1658 abort: cannot follow file not in parent revision: "a"
1659 abort: cannot follow file not in parent revision: "a"
1659 abort: cannot follow file not in parent revision: "a"
1660 abort: cannot follow file not in parent revision: "a"
1660 abort: cannot follow file not in parent revision: "a"
1661
1661
1662 Test --follow and patterns
1662 Test --follow and patterns
1663
1663
1664 $ testlog -f 'glob:*'
1664 $ testlog -f 'glob:*'
1665 abort: can only follow copies/renames for explicit filenames
1665 abort: can only follow copies/renames for explicit filenames
1666 abort: can only follow copies/renames for explicit filenames
1666 abort: can only follow copies/renames for explicit filenames
1667 abort: can only follow copies/renames for explicit filenames
1667 abort: can only follow copies/renames for explicit filenames
1668
1668
1669 Test --follow on a single rename
1669 Test --follow on a single rename
1670
1670
1671 $ hg up -q 2
1671 $ hg up -q 2
1672 $ testlog -f a
1672 $ testlog -f a
1673 []
1673 []
1674 (group
1674 (group
1675 (group
1675 (group
1676 (func
1676 (func
1677 ('symbol', 'follow')
1677 ('symbol', 'follow')
1678 ('string', 'a'))))
1678 ('string', 'a'))))
1679
1679
1680 Test --follow and multiple renames
1680 Test --follow and multiple renames
1681
1681
1682 $ hg up -q tip
1682 $ hg up -q tip
1683 $ testlog -f e
1683 $ testlog -f e
1684 []
1684 []
1685 (group
1685 (group
1686 (group
1686 (group
1687 (func
1687 (func
1688 ('symbol', 'follow')
1688 ('symbol', 'follow')
1689 ('string', 'e'))))
1689 ('string', 'e'))))
1690
1690
1691 Test --follow and multiple filelog heads
1691 Test --follow and multiple filelog heads
1692
1692
1693 $ hg up -q 2
1693 $ hg up -q 2
1694 $ testlog -f g
1694 $ testlog -f g
1695 []
1695 []
1696 (group
1696 (group
1697 (group
1697 (group
1698 (func
1698 (func
1699 ('symbol', 'follow')
1699 ('symbol', 'follow')
1700 ('string', 'g'))))
1700 ('string', 'g'))))
1701 $ cat log.nodes
1701 $ cat log.nodes
1702 nodetag 2
1702 nodetag 2
1703 nodetag 1
1703 nodetag 1
1704 nodetag 0
1704 nodetag 0
1705 $ hg up -q tip
1705 $ hg up -q tip
1706 $ testlog -f g
1706 $ testlog -f g
1707 []
1707 []
1708 (group
1708 (group
1709 (group
1709 (group
1710 (func
1710 (func
1711 ('symbol', 'follow')
1711 ('symbol', 'follow')
1712 ('string', 'g'))))
1712 ('string', 'g'))))
1713 $ cat log.nodes
1713 $ cat log.nodes
1714 nodetag 3
1714 nodetag 3
1715 nodetag 2
1715 nodetag 2
1716 nodetag 0
1716 nodetag 0
1717
1717
1718 Test --follow and multiple files
1718 Test --follow and multiple files
1719
1719
1720 $ testlog -f g e
1720 $ testlog -f g e
1721 []
1721 []
1722 (group
1722 (group
1723 (group
1723 (group
1724 (or
1724 (or
1725 (func
1725 (func
1726 ('symbol', 'follow')
1726 ('symbol', 'follow')
1727 ('string', 'g'))
1727 ('string', 'g'))
1728 (func
1728 (func
1729 ('symbol', 'follow')
1729 ('symbol', 'follow')
1730 ('string', 'e')))))
1730 ('string', 'e')))))
1731 $ cat log.nodes
1731 $ cat log.nodes
1732 nodetag 4
1732 nodetag 4
1733 nodetag 3
1733 nodetag 3
1734 nodetag 2
1734 nodetag 2
1735 nodetag 1
1735 nodetag 1
1736 nodetag 0
1736 nodetag 0
1737
1737
1738 Test --follow-first
1738 Test --follow-first
1739
1739
1740 $ hg up -q 3
1740 $ hg up -q 3
1741 $ echo ee > e
1741 $ echo ee > e
1742 $ hg ci -Am "add another e" e
1742 $ hg ci -Am "add another e" e
1743 created new head
1743 created new head
1744 $ hg merge --tool internal:other 4
1744 $ hg merge --tool internal:other 4
1745 0 files updated, 1 files merged, 1 files removed, 0 files unresolved
1745 0 files updated, 1 files merged, 1 files removed, 0 files unresolved
1746 (branch merge, don't forget to commit)
1746 (branch merge, don't forget to commit)
1747 $ echo merge > e
1747 $ echo merge > e
1748 $ hg ci -m "merge 5 and 4"
1748 $ hg ci -m "merge 5 and 4"
1749 $ testlog --follow-first
1749 $ testlog --follow-first
1750 []
1750 []
1751 (group
1751 (group
1752 (func
1752 (func
1753 ('symbol', '_firstancestors')
1753 ('symbol', '_firstancestors')
1754 ('symbol', '6')))
1754 ('symbol', '6')))
1755
1755
1756 Cannot compare with log --follow-first FILE as it never worked
1756 Cannot compare with log --follow-first FILE as it never worked
1757
1757
1758 $ hg log -G --print-revset --follow-first e
1758 $ hg log -G --print-revset --follow-first e
1759 []
1759 []
1760 (group
1760 (group
1761 (group
1761 (group
1762 (func
1762 (func
1763 ('symbol', '_followfirst')
1763 ('symbol', '_followfirst')
1764 ('string', 'e'))))
1764 ('string', 'e'))))
1765 $ hg log -G --follow-first e --template '{rev} {desc|firstline}\n'
1765 $ hg log -G --follow-first e --template '{rev} {desc|firstline}\n'
1766 @ 6 merge 5 and 4
1766 @ 6 merge 5 and 4
1767 |\
1767 |\
1768 o | 5 add another e
1768 o | 5 add another e
1769 | |
1769 | |
1770
1770
1771 Test --copies
1771 Test --copies
1772
1772
1773 $ hg log -G --copies --template "{rev} {desc|firstline} \
1773 $ hg log -G --copies --template "{rev} {desc|firstline} \
1774 > copies: {file_copies_switch}\n"
1774 > copies: {file_copies_switch}\n"
1775 @ 6 merge 5 and 4 copies:
1775 @ 6 merge 5 and 4 copies:
1776 |\
1776 |\
1777 | o 5 add another e copies:
1777 | o 5 add another e copies:
1778 | |
1778 | |
1779 o | 4 mv dir/b e copies: e (dir/b)
1779 o | 4 mv dir/b e copies: e (dir/b)
1780 |/
1780 |/
1781 o 3 mv a b; add d copies: b (a)g (f)
1781 o 3 mv a b; add d copies: b (a)g (f)
1782 |
1782 |
1783 o 2 mv b dir/b copies: dir/b (b)
1783 o 2 mv b dir/b copies: dir/b (b)
1784 |
1784 |
1785 o 1 copy a b copies: b (a)g (f)
1785 o 1 copy a b copies: b (a)g (f)
1786 |
1786 |
1787 o 0 add a copies:
1787 o 0 add a copies:
1788
1788
1789 Test "set:..." and parent revision
1789 Test "set:..." and parent revision
1790
1790
1791 $ hg up -q 4
1791 $ hg up -q 4
1792 $ testlog "set:copied()"
1792 $ testlog "set:copied()"
1793 []
1793 []
1794 (group
1794 (group
1795 (func
1795 (func
1796 ('symbol', '_matchfiles')
1796 ('symbol', '_matchfiles')
1797 (list
1797 (list
1798 (list
1798 (list
1799 ('string', 'r:')
1799 ('string', 'r:')
1800 ('string', 'd:relpath'))
1800 ('string', 'd:relpath'))
1801 ('string', 'p:set:copied()'))))
1801 ('string', 'p:set:copied()'))))
1802 $ testlog --include "set:copied()"
1802 $ testlog --include "set:copied()"
1803 []
1803 []
1804 (group
1804 (group
1805 (func
1805 (func
1806 ('symbol', '_matchfiles')
1806 ('symbol', '_matchfiles')
1807 (list
1807 (list
1808 (list
1808 (list
1809 ('string', 'r:')
1809 ('string', 'r:')
1810 ('string', 'd:relpath'))
1810 ('string', 'd:relpath'))
1811 ('string', 'i:set:copied()'))))
1811 ('string', 'i:set:copied()'))))
1812 $ testlog -r "sort(file('set:copied()'), -rev)"
1812 $ testlog -r "sort(file('set:copied()'), -rev)"
1813 ["sort(file('set:copied()'), -rev)"]
1813 ["sort(file('set:copied()'), -rev)"]
1814 []
1814 []
1815
1815
1816 Test --removed
1816 Test --removed
1817
1817
1818 $ testlog --removed
1818 $ testlog --removed
1819 []
1819 []
1820 []
1820 []
1821 $ testlog --removed a
1821 $ testlog --removed a
1822 []
1822 []
1823 (group
1823 (group
1824 (func
1824 (func
1825 ('symbol', '_matchfiles')
1825 ('symbol', '_matchfiles')
1826 (list
1826 (list
1827 (list
1827 (list
1828 ('string', 'r:')
1828 ('string', 'r:')
1829 ('string', 'd:relpath'))
1829 ('string', 'd:relpath'))
1830 ('string', 'p:a'))))
1830 ('string', 'p:a'))))
1831 $ testlog --removed --follow a
1831 $ testlog --removed --follow a
1832 abort: can only follow copies/renames for explicit filenames
1832 abort: can only follow copies/renames for explicit filenames
1833 abort: can only follow copies/renames for explicit filenames
1833 abort: can only follow copies/renames for explicit filenames
1834 abort: can only follow copies/renames for explicit filenames
1834 abort: can only follow copies/renames for explicit filenames
1835
1835
1836 Test --patch and --stat with --follow and --follow-first
1836 Test --patch and --stat with --follow and --follow-first
1837
1837
1838 $ hg up -q 3
1838 $ hg up -q 3
1839 $ hg log -G --git --patch b
1839 $ hg log -G --git --patch b
1840 o changeset: 1:216d4c92cf98
1840 o changeset: 1:216d4c92cf98
1841 | user: test
1841 | user: test
1842 | date: Thu Jan 01 00:00:00 1970 +0000
1842 | date: Thu Jan 01 00:00:00 1970 +0000
1843 | summary: copy a b
1843 | summary: copy a b
1844 |
1844 |
1845 | diff --git a/a b/b
1845 | diff --git a/a b/b
1846 | copy from a
1846 | copy from a
1847 | copy to b
1847 | copy to b
1848 |
1848 |
1849
1849
1850 $ hg log -G --git --stat b
1850 $ hg log -G --git --stat b
1851 o changeset: 1:216d4c92cf98
1851 o changeset: 1:216d4c92cf98
1852 | user: test
1852 | user: test
1853 | date: Thu Jan 01 00:00:00 1970 +0000
1853 | date: Thu Jan 01 00:00:00 1970 +0000
1854 | summary: copy a b
1854 | summary: copy a b
1855 |
1855 |
1856 | a | 0
1856 | a | 0
1857 | 1 files changed, 0 insertions(+), 0 deletions(-)
1857 | 1 files changed, 0 insertions(+), 0 deletions(-)
1858 |
1858 |
1859
1859
1860 $ hg log -G --git --patch --follow b
1860 $ hg log -G --git --patch --follow b
1861 o changeset: 1:216d4c92cf98
1861 o changeset: 1:216d4c92cf98
1862 | user: test
1862 | user: test
1863 | date: Thu Jan 01 00:00:00 1970 +0000
1863 | date: Thu Jan 01 00:00:00 1970 +0000
1864 | summary: copy a b
1864 | summary: copy a b
1865 |
1865 |
1866 | diff --git a/a b/b
1866 | diff --git a/a b/b
1867 | copy from a
1867 | copy from a
1868 | copy to b
1868 | copy to b
1869 |
1869 |
1870 o changeset: 0:f8035bb17114
1870 o changeset: 0:f8035bb17114
1871 user: test
1871 user: test
1872 date: Thu Jan 01 00:00:00 1970 +0000
1872 date: Thu Jan 01 00:00:00 1970 +0000
1873 summary: add a
1873 summary: add a
1874
1874
1875 diff --git a/a b/a
1875 diff --git a/a b/a
1876 new file mode 100644
1876 new file mode 100644
1877 --- /dev/null
1877 --- /dev/null
1878 +++ b/a
1878 +++ b/a
1879 @@ -0,0 +1,1 @@
1879 @@ -0,0 +1,1 @@
1880 +a
1880 +a
1881
1881
1882
1882
1883 $ hg log -G --git --stat --follow b
1883 $ hg log -G --git --stat --follow b
1884 o changeset: 1:216d4c92cf98
1884 o changeset: 1:216d4c92cf98
1885 | user: test
1885 | user: test
1886 | date: Thu Jan 01 00:00:00 1970 +0000
1886 | date: Thu Jan 01 00:00:00 1970 +0000
1887 | summary: copy a b
1887 | summary: copy a b
1888 |
1888 |
1889 | a | 0
1889 | a | 0
1890 | 1 files changed, 0 insertions(+), 0 deletions(-)
1890 | 1 files changed, 0 insertions(+), 0 deletions(-)
1891 |
1891 |
1892 o changeset: 0:f8035bb17114
1892 o changeset: 0:f8035bb17114
1893 user: test
1893 user: test
1894 date: Thu Jan 01 00:00:00 1970 +0000
1894 date: Thu Jan 01 00:00:00 1970 +0000
1895 summary: add a
1895 summary: add a
1896
1896
1897 a | 1 +
1897 a | 1 +
1898 1 files changed, 1 insertions(+), 0 deletions(-)
1898 1 files changed, 1 insertions(+), 0 deletions(-)
1899
1899
1900
1900
1901 $ hg up -q 6
1901 $ hg up -q 6
1902 $ hg log -G --git --patch --follow-first e
1902 $ hg log -G --git --patch --follow-first e
1903 @ changeset: 6:fc281d8ff18d
1903 @ changeset: 6:fc281d8ff18d
1904 |\ tag: tip
1904 |\ tag: tip
1905 | | parent: 5:99b31f1c2782
1905 | | parent: 5:99b31f1c2782
1906 | | parent: 4:17d952250a9d
1906 | | parent: 4:17d952250a9d
1907 | | user: test
1907 | | user: test
1908 | | date: Thu Jan 01 00:00:00 1970 +0000
1908 | | date: Thu Jan 01 00:00:00 1970 +0000
1909 | | summary: merge 5 and 4
1909 | | summary: merge 5 and 4
1910 | |
1910 | |
1911 | | diff --git a/e b/e
1911 | | diff --git a/e b/e
1912 | | --- a/e
1912 | | --- a/e
1913 | | +++ b/e
1913 | | +++ b/e
1914 | | @@ -1,1 +1,1 @@
1914 | | @@ -1,1 +1,1 @@
1915 | | -ee
1915 | | -ee
1916 | | +merge
1916 | | +merge
1917 | |
1917 | |
1918 o | changeset: 5:99b31f1c2782
1918 o | changeset: 5:99b31f1c2782
1919 | | parent: 3:5918b8d165d1
1919 | | parent: 3:5918b8d165d1
1920 | | user: test
1920 | | user: test
1921 | | date: Thu Jan 01 00:00:00 1970 +0000
1921 | | date: Thu Jan 01 00:00:00 1970 +0000
1922 | | summary: add another e
1922 | | summary: add another e
1923 | |
1923 | |
1924 | | diff --git a/e b/e
1924 | | diff --git a/e b/e
1925 | | new file mode 100644
1925 | | new file mode 100644
1926 | | --- /dev/null
1926 | | --- /dev/null
1927 | | +++ b/e
1927 | | +++ b/e
1928 | | @@ -0,0 +1,1 @@
1928 | | @@ -0,0 +1,1 @@
1929 | | +ee
1929 | | +ee
1930 | |
1930 | |
1931
1931
1932 Test old-style --rev
1932 Test old-style --rev
1933
1933
1934 $ hg tag 'foo-bar'
1934 $ hg tag 'foo-bar'
1935 $ testlog -r 'foo-bar'
1935 $ testlog -r 'foo-bar'
1936 ['foo-bar']
1936 ['foo-bar']
1937 []
1937 []
1938
1938
1939 Test --follow and forward --rev
1939 Test --follow and forward --rev
1940
1940
1941 $ hg up -q 6
1941 $ hg up -q 6
1942 $ echo g > g
1942 $ echo g > g
1943 $ hg ci -Am 'add g' g
1943 $ hg ci -Am 'add g' g
1944 created new head
1944 created new head
1945 $ hg up -q 2
1945 $ hg up -q 2
1946 $ hg log -G --template "{rev} {desc|firstline}\n"
1946 $ hg log -G --template "{rev} {desc|firstline}\n"
1947 o 8 add g
1947 o 8 add g
1948 |
1948 |
1949 | o 7 Added tag foo-bar for changeset fc281d8ff18d
1949 | o 7 Added tag foo-bar for changeset fc281d8ff18d
1950 |/
1950 |/
1951 o 6 merge 5 and 4
1951 o 6 merge 5 and 4
1952 |\
1952 |\
1953 | o 5 add another e
1953 | o 5 add another e
1954 | |
1954 | |
1955 o | 4 mv dir/b e
1955 o | 4 mv dir/b e
1956 |/
1956 |/
1957 o 3 mv a b; add d
1957 o 3 mv a b; add d
1958 |
1958 |
1959 @ 2 mv b dir/b
1959 @ 2 mv b dir/b
1960 |
1960 |
1961 o 1 copy a b
1961 o 1 copy a b
1962 |
1962 |
1963 o 0 add a
1963 o 0 add a
1964
1964
1965 $ testlog --follow -r6 -r8 -r5 -r7 -r4
1965 $ testlog --follow -r6 -r8 -r5 -r7 -r4
1966 ['6', '8', '5', '7', '4']
1966 ['6', '8', '5', '7', '4']
1967 (group
1967 (group
1968 (func
1968 (func
1969 ('symbol', 'descendants')
1969 ('symbol', 'descendants')
1970 ('symbol', '6')))
1970 ('symbol', '6')))
1971 --- log.nodes * (glob)
1971 --- log.nodes * (glob)
1972 +++ glog.nodes * (glob)
1972 +++ glog.nodes * (glob)
1973 @@ -1,3 +1,3 @@
1973 @@ -1,3 +1,3 @@
1974 -nodetag 6
1974 -nodetag 6
1975 nodetag 8
1975 nodetag 8
1976 nodetag 7
1976 nodetag 7
1977 +nodetag 6
1977 +nodetag 6
1978
1978
1979 Test --follow-first and forward --rev
1979 Test --follow-first and forward --rev
1980
1980
1981 $ testlog --follow-first -r6 -r8 -r5 -r7 -r4
1981 $ testlog --follow-first -r6 -r8 -r5 -r7 -r4
1982 ['6', '8', '5', '7', '4']
1982 ['6', '8', '5', '7', '4']
1983 (group
1983 (group
1984 (func
1984 (func
1985 ('symbol', '_firstdescendants')
1985 ('symbol', '_firstdescendants')
1986 ('symbol', '6')))
1986 ('symbol', '6')))
1987 --- log.nodes * (glob)
1987 --- log.nodes * (glob)
1988 +++ glog.nodes * (glob)
1988 +++ glog.nodes * (glob)
1989 @@ -1,3 +1,3 @@
1989 @@ -1,3 +1,3 @@
1990 -nodetag 6
1990 -nodetag 6
1991 nodetag 8
1991 nodetag 8
1992 nodetag 7
1992 nodetag 7
1993 +nodetag 6
1993 +nodetag 6
1994
1994
1995 Test --follow and backward --rev
1995 Test --follow and backward --rev
1996
1996
1997 $ testlog --follow -r6 -r5 -r7 -r8 -r4
1997 $ testlog --follow -r6 -r5 -r7 -r8 -r4
1998 ['6', '5', '7', '8', '4']
1998 ['6', '5', '7', '8', '4']
1999 (group
1999 (group
2000 (func
2000 (func
2001 ('symbol', 'ancestors')
2001 ('symbol', 'ancestors')
2002 ('symbol', '6')))
2002 ('symbol', '6')))
2003
2003
2004 Test --follow-first and backward --rev
2004 Test --follow-first and backward --rev
2005
2005
2006 $ testlog --follow-first -r6 -r5 -r7 -r8 -r4
2006 $ testlog --follow-first -r6 -r5 -r7 -r8 -r4
2007 ['6', '5', '7', '8', '4']
2007 ['6', '5', '7', '8', '4']
2008 (group
2008 (group
2009 (func
2009 (func
2010 ('symbol', '_firstancestors')
2010 ('symbol', '_firstancestors')
2011 ('symbol', '6')))
2011 ('symbol', '6')))
2012
2012
2013 Test subdir
2013 Test subdir
2014
2014
2015 $ hg up -q 3
2015 $ hg up -q 3
2016 $ cd dir
2016 $ cd dir
2017 $ testlog .
2017 $ testlog .
2018 []
2018 []
2019 (group
2019 (group
2020 (func
2020 (func
2021 ('symbol', '_matchfiles')
2021 ('symbol', '_matchfiles')
2022 (list
2022 (list
2023 (list
2023 (list
2024 ('string', 'r:')
2024 ('string', 'r:')
2025 ('string', 'd:relpath'))
2025 ('string', 'd:relpath'))
2026 ('string', 'p:.'))))
2026 ('string', 'p:.'))))
2027 $ testlog ../b
2027 $ testlog ../b
2028 []
2028 []
2029 (group
2029 (group
2030 (group
2030 (group
2031 (func
2031 (func
2032 ('symbol', 'filelog')
2032 ('symbol', 'filelog')
2033 ('string', '../b'))))
2033 ('string', '../b'))))
2034 $ testlog -f ../b
2034 $ testlog -f ../b
2035 []
2035 []
2036 (group
2036 (group
2037 (group
2037 (group
2038 (func
2038 (func
2039 ('symbol', 'follow')
2039 ('symbol', 'follow')
2040 ('string', 'b'))))
2040 ('string', 'b'))))
2041 $ cd ..
2041 $ cd ..
2042
2042
2043 Test --hidden
2043 Test --hidden
2044 (enable obsolete)
2044 (enable obsolete)
2045
2045
2046 $ cat > ${TESTTMP}/obs.py << EOF
2046 $ cat > ${TESTTMP}/obs.py << EOF
2047 > import mercurial.obsolete
2047 > import mercurial.obsolete
2048 > mercurial.obsolete._enabled = True
2048 > mercurial.obsolete._enabled = True
2049 > EOF
2049 > EOF
2050 $ echo '[extensions]' >> $HGRCPATH
2050 $ echo '[extensions]' >> $HGRCPATH
2051 $ echo "obs=${TESTTMP}/obs.py" >> $HGRCPATH
2051 $ echo "obs=${TESTTMP}/obs.py" >> $HGRCPATH
2052
2052
2053 $ hg debugobsolete `hg id --debug -i -r 8`
2053 $ hg debugobsolete `hg id --debug -i -r 8`
2054 $ testlog
2054 $ testlog
2055 []
2055 []
2056 []
2056 []
2057 $ testlog --hidden
2057 $ testlog --hidden
2058 []
2058 []
2059 []
2059 []
2060 $ hg log -G --template '{rev} {desc}\n'
2060 $ hg log -G --template '{rev} {desc}\n'
2061 o 7 Added tag foo-bar for changeset fc281d8ff18d
2061 o 7 Added tag foo-bar for changeset fc281d8ff18d
2062 |
2062 |
2063 o 6 merge 5 and 4
2063 o 6 merge 5 and 4
2064 |\
2064 |\
2065 | o 5 add another e
2065 | o 5 add another e
2066 | |
2066 | |
2067 o | 4 mv dir/b e
2067 o | 4 mv dir/b e
2068 |/
2068 |/
2069 @ 3 mv a b; add d
2069 @ 3 mv a b; add d
2070 |
2070 |
2071 o 2 mv b dir/b
2071 o 2 mv b dir/b
2072 |
2072 |
2073 o 1 copy a b
2073 o 1 copy a b
2074 |
2074 |
2075 o 0 add a
2075 o 0 add a
2076
2076
2077
2077
2078 A template without trailing newline should do something sane
2078 A template without trailing newline should do something sane
2079
2079
2080 $ hg log -G -r ::2 --template '{rev} {desc}'
2080 $ hg log -G -r ::2 --template '{rev} {desc}'
2081 o 2 mv b dir/b
2081 o 2 mv b dir/b
2082 |
2082 |
2083 o 1 copy a b
2083 o 1 copy a b
2084 |
2084 |
2085 o 0 add a
2085 o 0 add a
2086
2086
2087
2087
2088 Extra newlines must be preserved
2088 Extra newlines must be preserved
2089
2089
2090 $ hg log -G -r ::2 --template '\n{rev} {desc}\n\n'
2090 $ hg log -G -r ::2 --template '\n{rev} {desc}\n\n'
2091 o
2091 o
2092 | 2 mv b dir/b
2092 | 2 mv b dir/b
2093 |
2093 |
2094 o
2094 o
2095 | 1 copy a b
2095 | 1 copy a b
2096 |
2096 |
2097 o
2097 o
2098 0 add a
2098 0 add a
2099
2099
2100
2100
2101 The almost-empty template should do something sane too ...
2101 The almost-empty template should do something sane too ...
2102
2102
2103 $ hg log -G -r ::2 --template '\n'
2103 $ hg log -G -r ::2 --template '\n'
2104 o
2104 o
2105 |
2105 |
2106 o
2106 o
2107 |
2107 |
2108 o
2108 o
2109
2109
2110
2110
2111 issue3772
2111 issue3772
2112
2112
2113 $ hg log -G -r :null
2113 $ hg log -G -r :null
2114 o changeset: 0:f8035bb17114
2115 | user: test
2116 | date: Thu Jan 01 00:00:00 1970 +0000
2117 | summary: add a
2118 |
2114 o changeset: -1:000000000000
2119 o changeset: -1:000000000000
2115 user:
2120 user:
2116 date: Thu Jan 01 00:00:00 1970 +0000
2121 date: Thu Jan 01 00:00:00 1970 +0000
2117
2122
2118 $ hg log -G -r null:null
2123 $ hg log -G -r null:null
2119 o changeset: -1:000000000000
2124 o changeset: -1:000000000000
2120 user:
2125 user:
2121 date: Thu Jan 01 00:00:00 1970 +0000
2126 date: Thu Jan 01 00:00:00 1970 +0000
2122
2127
2123
2128
2124 $ cd ..
2129 $ cd ..
@@ -1,1369 +1,1375 b''
1 Log on empty repository: checking consistency
1 Log on empty repository: checking consistency
2
2
3 $ hg init empty
3 $ hg init empty
4 $ cd empty
4 $ cd empty
5 $ hg log
5 $ hg log
6 $ hg log -r 1
6 $ hg log -r 1
7 abort: unknown revision '1'!
7 abort: unknown revision '1'!
8 [255]
8 [255]
9 $ hg log -r -1:0
9 $ hg log -r -1:0
10 abort: unknown revision '-1'!
10 abort: unknown revision '-1'!
11 [255]
11 [255]
12 $ hg log -r 'branch(name)'
12 $ hg log -r 'branch(name)'
13 abort: unknown revision 'name'!
13 abort: unknown revision 'name'!
14 [255]
14 [255]
15 $ hg log -r null -q
15 $ hg log -r null -q
16 -1:000000000000
16 -1:000000000000
17
17
18 The g is crafted to have 2 filelog topological heads in a linear
18 The g is crafted to have 2 filelog topological heads in a linear
19 changeset graph
19 changeset graph
20
20
21 $ hg init a
21 $ hg init a
22 $ cd a
22 $ cd a
23 $ echo a > a
23 $ echo a > a
24 $ echo f > f
24 $ echo f > f
25 $ hg ci -Ama -d '1 0'
25 $ hg ci -Ama -d '1 0'
26 adding a
26 adding a
27 adding f
27 adding f
28
28
29 $ hg cp a b
29 $ hg cp a b
30 $ hg cp f g
30 $ hg cp f g
31 $ hg ci -mb -d '2 0'
31 $ hg ci -mb -d '2 0'
32
32
33 $ mkdir dir
33 $ mkdir dir
34 $ hg mv b dir
34 $ hg mv b dir
35 $ echo g >> g
35 $ echo g >> g
36 $ echo f >> f
36 $ echo f >> f
37 $ hg ci -mc -d '3 0'
37 $ hg ci -mc -d '3 0'
38
38
39 $ hg mv a b
39 $ hg mv a b
40 $ hg cp -f f g
40 $ hg cp -f f g
41 $ echo a > d
41 $ echo a > d
42 $ hg add d
42 $ hg add d
43 $ hg ci -md -d '4 0'
43 $ hg ci -md -d '4 0'
44
44
45 $ hg mv dir/b e
45 $ hg mv dir/b e
46 $ hg ci -me -d '5 0'
46 $ hg ci -me -d '5 0'
47
47
48 $ hg log a
48 $ hg log a
49 changeset: 0:9161b9aeaf16
49 changeset: 0:9161b9aeaf16
50 user: test
50 user: test
51 date: Thu Jan 01 00:00:01 1970 +0000
51 date: Thu Jan 01 00:00:01 1970 +0000
52 summary: a
52 summary: a
53
53
54 log on directory
54 log on directory
55
55
56 $ hg log dir
56 $ hg log dir
57 changeset: 4:7e4639b4691b
57 changeset: 4:7e4639b4691b
58 tag: tip
58 tag: tip
59 user: test
59 user: test
60 date: Thu Jan 01 00:00:05 1970 +0000
60 date: Thu Jan 01 00:00:05 1970 +0000
61 summary: e
61 summary: e
62
62
63 changeset: 2:f8954cd4dc1f
63 changeset: 2:f8954cd4dc1f
64 user: test
64 user: test
65 date: Thu Jan 01 00:00:03 1970 +0000
65 date: Thu Jan 01 00:00:03 1970 +0000
66 summary: c
66 summary: c
67
67
68 $ hg log somethingthatdoesntexist dir
68 $ hg log somethingthatdoesntexist dir
69 changeset: 4:7e4639b4691b
69 changeset: 4:7e4639b4691b
70 tag: tip
70 tag: tip
71 user: test
71 user: test
72 date: Thu Jan 01 00:00:05 1970 +0000
72 date: Thu Jan 01 00:00:05 1970 +0000
73 summary: e
73 summary: e
74
74
75 changeset: 2:f8954cd4dc1f
75 changeset: 2:f8954cd4dc1f
76 user: test
76 user: test
77 date: Thu Jan 01 00:00:03 1970 +0000
77 date: Thu Jan 01 00:00:03 1970 +0000
78 summary: c
78 summary: c
79
79
80
80
81 -f, directory
81 -f, directory
82
82
83 $ hg log -f dir
83 $ hg log -f dir
84 abort: cannot follow file not in parent revision: "dir"
84 abort: cannot follow file not in parent revision: "dir"
85 [255]
85 [255]
86
86
87 -f, a wrong style
87 -f, a wrong style
88
88
89 $ hg log -f -l1 --style something
89 $ hg log -f -l1 --style something
90 abort: style 'something' not found
90 abort: style 'something' not found
91 (available styles: bisect, changelog, compact, default, phases, xml)
91 (available styles: bisect, changelog, compact, default, phases, xml)
92 [255]
92 [255]
93
93
94 -f, phases style
94 -f, phases style
95
95
96
96
97 $ hg log -f -l1 --style phases
97 $ hg log -f -l1 --style phases
98 changeset: 4:7e4639b4691b
98 changeset: 4:7e4639b4691b
99 tag: tip
99 tag: tip
100 phase: draft
100 phase: draft
101 user: test
101 user: test
102 date: Thu Jan 01 00:00:05 1970 +0000
102 date: Thu Jan 01 00:00:05 1970 +0000
103 summary: e
103 summary: e
104
104
105
105
106 -f, but no args
106 -f, but no args
107
107
108 $ hg log -f
108 $ hg log -f
109 changeset: 4:7e4639b4691b
109 changeset: 4:7e4639b4691b
110 tag: tip
110 tag: tip
111 user: test
111 user: test
112 date: Thu Jan 01 00:00:05 1970 +0000
112 date: Thu Jan 01 00:00:05 1970 +0000
113 summary: e
113 summary: e
114
114
115 changeset: 3:2ca5ba701980
115 changeset: 3:2ca5ba701980
116 user: test
116 user: test
117 date: Thu Jan 01 00:00:04 1970 +0000
117 date: Thu Jan 01 00:00:04 1970 +0000
118 summary: d
118 summary: d
119
119
120 changeset: 2:f8954cd4dc1f
120 changeset: 2:f8954cd4dc1f
121 user: test
121 user: test
122 date: Thu Jan 01 00:00:03 1970 +0000
122 date: Thu Jan 01 00:00:03 1970 +0000
123 summary: c
123 summary: c
124
124
125 changeset: 1:d89b0a12d229
125 changeset: 1:d89b0a12d229
126 user: test
126 user: test
127 date: Thu Jan 01 00:00:02 1970 +0000
127 date: Thu Jan 01 00:00:02 1970 +0000
128 summary: b
128 summary: b
129
129
130 changeset: 0:9161b9aeaf16
130 changeset: 0:9161b9aeaf16
131 user: test
131 user: test
132 date: Thu Jan 01 00:00:01 1970 +0000
132 date: Thu Jan 01 00:00:01 1970 +0000
133 summary: a
133 summary: a
134
134
135
135
136 one rename
136 one rename
137
137
138 $ hg up -q 2
138 $ hg up -q 2
139 $ hg log -vf a
139 $ hg log -vf a
140 changeset: 0:9161b9aeaf16
140 changeset: 0:9161b9aeaf16
141 user: test
141 user: test
142 date: Thu Jan 01 00:00:01 1970 +0000
142 date: Thu Jan 01 00:00:01 1970 +0000
143 files: a f
143 files: a f
144 description:
144 description:
145 a
145 a
146
146
147
147
148
148
149 many renames
149 many renames
150
150
151 $ hg up -q tip
151 $ hg up -q tip
152 $ hg log -vf e
152 $ hg log -vf e
153 changeset: 4:7e4639b4691b
153 changeset: 4:7e4639b4691b
154 tag: tip
154 tag: tip
155 user: test
155 user: test
156 date: Thu Jan 01 00:00:05 1970 +0000
156 date: Thu Jan 01 00:00:05 1970 +0000
157 files: dir/b e
157 files: dir/b e
158 description:
158 description:
159 e
159 e
160
160
161
161
162 changeset: 2:f8954cd4dc1f
162 changeset: 2:f8954cd4dc1f
163 user: test
163 user: test
164 date: Thu Jan 01 00:00:03 1970 +0000
164 date: Thu Jan 01 00:00:03 1970 +0000
165 files: b dir/b f g
165 files: b dir/b f g
166 description:
166 description:
167 c
167 c
168
168
169
169
170 changeset: 1:d89b0a12d229
170 changeset: 1:d89b0a12d229
171 user: test
171 user: test
172 date: Thu Jan 01 00:00:02 1970 +0000
172 date: Thu Jan 01 00:00:02 1970 +0000
173 files: b g
173 files: b g
174 description:
174 description:
175 b
175 b
176
176
177
177
178 changeset: 0:9161b9aeaf16
178 changeset: 0:9161b9aeaf16
179 user: test
179 user: test
180 date: Thu Jan 01 00:00:01 1970 +0000
180 date: Thu Jan 01 00:00:01 1970 +0000
181 files: a f
181 files: a f
182 description:
182 description:
183 a
183 a
184
184
185
185
186
186
187
187
188 log -pf dir/b
188 log -pf dir/b
189
189
190 $ hg up -q 3
190 $ hg up -q 3
191 $ hg log -pf dir/b
191 $ hg log -pf dir/b
192 changeset: 2:f8954cd4dc1f
192 changeset: 2:f8954cd4dc1f
193 user: test
193 user: test
194 date: Thu Jan 01 00:00:03 1970 +0000
194 date: Thu Jan 01 00:00:03 1970 +0000
195 summary: c
195 summary: c
196
196
197 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
197 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
198 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
198 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
199 +++ b/dir/b Thu Jan 01 00:00:03 1970 +0000
199 +++ b/dir/b Thu Jan 01 00:00:03 1970 +0000
200 @@ -0,0 +1,1 @@
200 @@ -0,0 +1,1 @@
201 +a
201 +a
202
202
203 changeset: 1:d89b0a12d229
203 changeset: 1:d89b0a12d229
204 user: test
204 user: test
205 date: Thu Jan 01 00:00:02 1970 +0000
205 date: Thu Jan 01 00:00:02 1970 +0000
206 summary: b
206 summary: b
207
207
208 diff -r 9161b9aeaf16 -r d89b0a12d229 b
208 diff -r 9161b9aeaf16 -r d89b0a12d229 b
209 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
209 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
210 +++ b/b Thu Jan 01 00:00:02 1970 +0000
210 +++ b/b Thu Jan 01 00:00:02 1970 +0000
211 @@ -0,0 +1,1 @@
211 @@ -0,0 +1,1 @@
212 +a
212 +a
213
213
214 changeset: 0:9161b9aeaf16
214 changeset: 0:9161b9aeaf16
215 user: test
215 user: test
216 date: Thu Jan 01 00:00:01 1970 +0000
216 date: Thu Jan 01 00:00:01 1970 +0000
217 summary: a
217 summary: a
218
218
219 diff -r 000000000000 -r 9161b9aeaf16 a
219 diff -r 000000000000 -r 9161b9aeaf16 a
220 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
220 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
221 +++ b/a Thu Jan 01 00:00:01 1970 +0000
221 +++ b/a Thu Jan 01 00:00:01 1970 +0000
222 @@ -0,0 +1,1 @@
222 @@ -0,0 +1,1 @@
223 +a
223 +a
224
224
225
225
226 log -vf dir/b
226 log -vf dir/b
227
227
228 $ hg log -vf dir/b
228 $ hg log -vf dir/b
229 changeset: 2:f8954cd4dc1f
229 changeset: 2:f8954cd4dc1f
230 user: test
230 user: test
231 date: Thu Jan 01 00:00:03 1970 +0000
231 date: Thu Jan 01 00:00:03 1970 +0000
232 files: b dir/b f g
232 files: b dir/b f g
233 description:
233 description:
234 c
234 c
235
235
236
236
237 changeset: 1:d89b0a12d229
237 changeset: 1:d89b0a12d229
238 user: test
238 user: test
239 date: Thu Jan 01 00:00:02 1970 +0000
239 date: Thu Jan 01 00:00:02 1970 +0000
240 files: b g
240 files: b g
241 description:
241 description:
242 b
242 b
243
243
244
244
245 changeset: 0:9161b9aeaf16
245 changeset: 0:9161b9aeaf16
246 user: test
246 user: test
247 date: Thu Jan 01 00:00:01 1970 +0000
247 date: Thu Jan 01 00:00:01 1970 +0000
248 files: a f
248 files: a f
249 description:
249 description:
250 a
250 a
251
251
252
252
253
253
254
254
255 -f and multiple filelog heads
255 -f and multiple filelog heads
256
256
257 $ hg up -q 2
257 $ hg up -q 2
258 $ hg log -f g --template '{rev}\n'
258 $ hg log -f g --template '{rev}\n'
259 2
259 2
260 1
260 1
261 0
261 0
262 $ hg up -q tip
262 $ hg up -q tip
263 $ hg log -f g --template '{rev}\n'
263 $ hg log -f g --template '{rev}\n'
264 3
264 3
265 2
265 2
266 0
266 0
267
267
268
268
269 log copies with --copies
269 log copies with --copies
270
270
271 $ hg log -vC --template '{rev} {file_copies}\n'
271 $ hg log -vC --template '{rev} {file_copies}\n'
272 4 e (dir/b)
272 4 e (dir/b)
273 3 b (a)g (f)
273 3 b (a)g (f)
274 2 dir/b (b)
274 2 dir/b (b)
275 1 b (a)g (f)
275 1 b (a)g (f)
276 0
276 0
277
277
278 log copies switch without --copies, with old filecopy template
278 log copies switch without --copies, with old filecopy template
279
279
280 $ hg log -v --template '{rev} {file_copies_switch%filecopy}\n'
280 $ hg log -v --template '{rev} {file_copies_switch%filecopy}\n'
281 4
281 4
282 3
282 3
283 2
283 2
284 1
284 1
285 0
285 0
286
286
287 log copies switch with --copies
287 log copies switch with --copies
288
288
289 $ hg log -vC --template '{rev} {file_copies_switch}\n'
289 $ hg log -vC --template '{rev} {file_copies_switch}\n'
290 4 e (dir/b)
290 4 e (dir/b)
291 3 b (a)g (f)
291 3 b (a)g (f)
292 2 dir/b (b)
292 2 dir/b (b)
293 1 b (a)g (f)
293 1 b (a)g (f)
294 0
294 0
295
295
296
296
297 log copies with hardcoded style and with --style=default
297 log copies with hardcoded style and with --style=default
298
298
299 $ hg log -vC -r4
299 $ hg log -vC -r4
300 changeset: 4:7e4639b4691b
300 changeset: 4:7e4639b4691b
301 tag: tip
301 tag: tip
302 user: test
302 user: test
303 date: Thu Jan 01 00:00:05 1970 +0000
303 date: Thu Jan 01 00:00:05 1970 +0000
304 files: dir/b e
304 files: dir/b e
305 copies: e (dir/b)
305 copies: e (dir/b)
306 description:
306 description:
307 e
307 e
308
308
309
309
310 $ hg log -vC -r4 --style=default
310 $ hg log -vC -r4 --style=default
311 changeset: 4:7e4639b4691b
311 changeset: 4:7e4639b4691b
312 tag: tip
312 tag: tip
313 user: test
313 user: test
314 date: Thu Jan 01 00:00:05 1970 +0000
314 date: Thu Jan 01 00:00:05 1970 +0000
315 files: dir/b e
315 files: dir/b e
316 copies: e (dir/b)
316 copies: e (dir/b)
317 description:
317 description:
318 e
318 e
319
319
320
320
321
321
322
322
323 log copies, non-linear manifest
323 log copies, non-linear manifest
324
324
325 $ hg up -C 3
325 $ hg up -C 3
326 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
326 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
327 $ hg mv dir/b e
327 $ hg mv dir/b e
328 $ echo foo > foo
328 $ echo foo > foo
329 $ hg ci -Ame2 -d '6 0'
329 $ hg ci -Ame2 -d '6 0'
330 adding foo
330 adding foo
331 created new head
331 created new head
332 $ hg log -v --template '{rev} {file_copies}\n' -r 5
332 $ hg log -v --template '{rev} {file_copies}\n' -r 5
333 5 e (dir/b)
333 5 e (dir/b)
334
334
335
335
336 log copies, execute bit set
336 log copies, execute bit set
337
337
338 #if execbit
338 #if execbit
339 $ chmod +x e
339 $ chmod +x e
340 $ hg ci -me3 -d '7 0'
340 $ hg ci -me3 -d '7 0'
341 $ hg log -v --template '{rev} {file_copies}\n' -r 6
341 $ hg log -v --template '{rev} {file_copies}\n' -r 6
342 6
342 6
343 #endif
343 #endif
344
344
345
345
346 log -p d
346 log -p d
347
347
348 $ hg log -pv d
348 $ hg log -pv d
349 changeset: 3:2ca5ba701980
349 changeset: 3:2ca5ba701980
350 user: test
350 user: test
351 date: Thu Jan 01 00:00:04 1970 +0000
351 date: Thu Jan 01 00:00:04 1970 +0000
352 files: a b d g
352 files: a b d g
353 description:
353 description:
354 d
354 d
355
355
356
356
357 diff -r f8954cd4dc1f -r 2ca5ba701980 d
357 diff -r f8954cd4dc1f -r 2ca5ba701980 d
358 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
358 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
359 +++ b/d Thu Jan 01 00:00:04 1970 +0000
359 +++ b/d Thu Jan 01 00:00:04 1970 +0000
360 @@ -0,0 +1,1 @@
360 @@ -0,0 +1,1 @@
361 +a
361 +a
362
362
363
363
364
364
365 log --removed file
365 log --removed file
366
366
367 $ hg log --removed -v a
367 $ hg log --removed -v a
368 changeset: 3:2ca5ba701980
368 changeset: 3:2ca5ba701980
369 user: test
369 user: test
370 date: Thu Jan 01 00:00:04 1970 +0000
370 date: Thu Jan 01 00:00:04 1970 +0000
371 files: a b d g
371 files: a b d g
372 description:
372 description:
373 d
373 d
374
374
375
375
376 changeset: 0:9161b9aeaf16
376 changeset: 0:9161b9aeaf16
377 user: test
377 user: test
378 date: Thu Jan 01 00:00:01 1970 +0000
378 date: Thu Jan 01 00:00:01 1970 +0000
379 files: a f
379 files: a f
380 description:
380 description:
381 a
381 a
382
382
383
383
384
384
385 log --removed revrange file
385 log --removed revrange file
386
386
387 $ hg log --removed -v -r0:2 a
387 $ hg log --removed -v -r0:2 a
388 changeset: 0:9161b9aeaf16
388 changeset: 0:9161b9aeaf16
389 user: test
389 user: test
390 date: Thu Jan 01 00:00:01 1970 +0000
390 date: Thu Jan 01 00:00:01 1970 +0000
391 files: a f
391 files: a f
392 description:
392 description:
393 a
393 a
394
394
395
395
396 $ cd ..
396 $ cd ..
397
397
398 log --follow tests
398 log --follow tests
399
399
400 $ hg init follow
400 $ hg init follow
401 $ cd follow
401 $ cd follow
402
402
403 $ echo base > base
403 $ echo base > base
404 $ hg ci -Ambase -d '1 0'
404 $ hg ci -Ambase -d '1 0'
405 adding base
405 adding base
406
406
407 $ echo r1 >> base
407 $ echo r1 >> base
408 $ hg ci -Amr1 -d '1 0'
408 $ hg ci -Amr1 -d '1 0'
409 $ echo r2 >> base
409 $ echo r2 >> base
410 $ hg ci -Amr2 -d '1 0'
410 $ hg ci -Amr2 -d '1 0'
411
411
412 $ hg up -C 1
412 $ hg up -C 1
413 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
413 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
414 $ echo b1 > b1
414 $ echo b1 > b1
415 $ hg ci -Amb1 -d '1 0'
415 $ hg ci -Amb1 -d '1 0'
416 adding b1
416 adding b1
417 created new head
417 created new head
418
418
419
419
420 log -f
420 log -f
421
421
422 $ hg log -f
422 $ hg log -f
423 changeset: 3:e62f78d544b4
423 changeset: 3:e62f78d544b4
424 tag: tip
424 tag: tip
425 parent: 1:3d5bf5654eda
425 parent: 1:3d5bf5654eda
426 user: test
426 user: test
427 date: Thu Jan 01 00:00:01 1970 +0000
427 date: Thu Jan 01 00:00:01 1970 +0000
428 summary: b1
428 summary: b1
429
429
430 changeset: 1:3d5bf5654eda
430 changeset: 1:3d5bf5654eda
431 user: test
431 user: test
432 date: Thu Jan 01 00:00:01 1970 +0000
432 date: Thu Jan 01 00:00:01 1970 +0000
433 summary: r1
433 summary: r1
434
434
435 changeset: 0:67e992f2c4f3
435 changeset: 0:67e992f2c4f3
436 user: test
436 user: test
437 date: Thu Jan 01 00:00:01 1970 +0000
437 date: Thu Jan 01 00:00:01 1970 +0000
438 summary: base
438 summary: base
439
439
440
440
441
441
442 log -f -r 1:tip
442 log -f -r 1:tip
443
443
444 $ hg up -C 0
444 $ hg up -C 0
445 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
445 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
446 $ echo b2 > b2
446 $ echo b2 > b2
447 $ hg ci -Amb2 -d '1 0'
447 $ hg ci -Amb2 -d '1 0'
448 adding b2
448 adding b2
449 created new head
449 created new head
450 $ hg log -f -r 1:tip
450 $ hg log -f -r 1:tip
451 changeset: 1:3d5bf5654eda
451 changeset: 1:3d5bf5654eda
452 user: test
452 user: test
453 date: Thu Jan 01 00:00:01 1970 +0000
453 date: Thu Jan 01 00:00:01 1970 +0000
454 summary: r1
454 summary: r1
455
455
456 changeset: 2:60c670bf5b30
456 changeset: 2:60c670bf5b30
457 user: test
457 user: test
458 date: Thu Jan 01 00:00:01 1970 +0000
458 date: Thu Jan 01 00:00:01 1970 +0000
459 summary: r2
459 summary: r2
460
460
461 changeset: 3:e62f78d544b4
461 changeset: 3:e62f78d544b4
462 parent: 1:3d5bf5654eda
462 parent: 1:3d5bf5654eda
463 user: test
463 user: test
464 date: Thu Jan 01 00:00:01 1970 +0000
464 date: Thu Jan 01 00:00:01 1970 +0000
465 summary: b1
465 summary: b1
466
466
467
467
468
468
469 log -r . with two parents
469 log -r . with two parents
470
470
471 $ hg up -C 3
471 $ hg up -C 3
472 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
472 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
473 $ hg merge tip
473 $ hg merge tip
474 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
474 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
475 (branch merge, don't forget to commit)
475 (branch merge, don't forget to commit)
476 $ hg log -r .
476 $ hg log -r .
477 changeset: 3:e62f78d544b4
477 changeset: 3:e62f78d544b4
478 parent: 1:3d5bf5654eda
478 parent: 1:3d5bf5654eda
479 user: test
479 user: test
480 date: Thu Jan 01 00:00:01 1970 +0000
480 date: Thu Jan 01 00:00:01 1970 +0000
481 summary: b1
481 summary: b1
482
482
483
483
484
484
485 log -r . with one parent
485 log -r . with one parent
486
486
487 $ hg ci -mm12 -d '1 0'
487 $ hg ci -mm12 -d '1 0'
488 $ hg log -r .
488 $ hg log -r .
489 changeset: 5:302e9dd6890d
489 changeset: 5:302e9dd6890d
490 tag: tip
490 tag: tip
491 parent: 3:e62f78d544b4
491 parent: 3:e62f78d544b4
492 parent: 4:ddb82e70d1a1
492 parent: 4:ddb82e70d1a1
493 user: test
493 user: test
494 date: Thu Jan 01 00:00:01 1970 +0000
494 date: Thu Jan 01 00:00:01 1970 +0000
495 summary: m12
495 summary: m12
496
496
497
497
498 $ echo postm >> b1
498 $ echo postm >> b1
499 $ hg ci -Amb1.1 -d'1 0'
499 $ hg ci -Amb1.1 -d'1 0'
500
500
501
501
502 log --follow-first
502 log --follow-first
503
503
504 $ hg log --follow-first
504 $ hg log --follow-first
505 changeset: 6:2404bbcab562
505 changeset: 6:2404bbcab562
506 tag: tip
506 tag: tip
507 user: test
507 user: test
508 date: Thu Jan 01 00:00:01 1970 +0000
508 date: Thu Jan 01 00:00:01 1970 +0000
509 summary: b1.1
509 summary: b1.1
510
510
511 changeset: 5:302e9dd6890d
511 changeset: 5:302e9dd6890d
512 parent: 3:e62f78d544b4
512 parent: 3:e62f78d544b4
513 parent: 4:ddb82e70d1a1
513 parent: 4:ddb82e70d1a1
514 user: test
514 user: test
515 date: Thu Jan 01 00:00:01 1970 +0000
515 date: Thu Jan 01 00:00:01 1970 +0000
516 summary: m12
516 summary: m12
517
517
518 changeset: 3:e62f78d544b4
518 changeset: 3:e62f78d544b4
519 parent: 1:3d5bf5654eda
519 parent: 1:3d5bf5654eda
520 user: test
520 user: test
521 date: Thu Jan 01 00:00:01 1970 +0000
521 date: Thu Jan 01 00:00:01 1970 +0000
522 summary: b1
522 summary: b1
523
523
524 changeset: 1:3d5bf5654eda
524 changeset: 1:3d5bf5654eda
525 user: test
525 user: test
526 date: Thu Jan 01 00:00:01 1970 +0000
526 date: Thu Jan 01 00:00:01 1970 +0000
527 summary: r1
527 summary: r1
528
528
529 changeset: 0:67e992f2c4f3
529 changeset: 0:67e992f2c4f3
530 user: test
530 user: test
531 date: Thu Jan 01 00:00:01 1970 +0000
531 date: Thu Jan 01 00:00:01 1970 +0000
532 summary: base
532 summary: base
533
533
534
534
535
535
536 log -P 2
536 log -P 2
537
537
538 $ hg log -P 2
538 $ hg log -P 2
539 changeset: 6:2404bbcab562
539 changeset: 6:2404bbcab562
540 tag: tip
540 tag: tip
541 user: test
541 user: test
542 date: Thu Jan 01 00:00:01 1970 +0000
542 date: Thu Jan 01 00:00:01 1970 +0000
543 summary: b1.1
543 summary: b1.1
544
544
545 changeset: 5:302e9dd6890d
545 changeset: 5:302e9dd6890d
546 parent: 3:e62f78d544b4
546 parent: 3:e62f78d544b4
547 parent: 4:ddb82e70d1a1
547 parent: 4:ddb82e70d1a1
548 user: test
548 user: test
549 date: Thu Jan 01 00:00:01 1970 +0000
549 date: Thu Jan 01 00:00:01 1970 +0000
550 summary: m12
550 summary: m12
551
551
552 changeset: 4:ddb82e70d1a1
552 changeset: 4:ddb82e70d1a1
553 parent: 0:67e992f2c4f3
553 parent: 0:67e992f2c4f3
554 user: test
554 user: test
555 date: Thu Jan 01 00:00:01 1970 +0000
555 date: Thu Jan 01 00:00:01 1970 +0000
556 summary: b2
556 summary: b2
557
557
558 changeset: 3:e62f78d544b4
558 changeset: 3:e62f78d544b4
559 parent: 1:3d5bf5654eda
559 parent: 1:3d5bf5654eda
560 user: test
560 user: test
561 date: Thu Jan 01 00:00:01 1970 +0000
561 date: Thu Jan 01 00:00:01 1970 +0000
562 summary: b1
562 summary: b1
563
563
564
564
565
565
566 log -r tip -p --git
566 log -r tip -p --git
567
567
568 $ hg log -r tip -p --git
568 $ hg log -r tip -p --git
569 changeset: 6:2404bbcab562
569 changeset: 6:2404bbcab562
570 tag: tip
570 tag: tip
571 user: test
571 user: test
572 date: Thu Jan 01 00:00:01 1970 +0000
572 date: Thu Jan 01 00:00:01 1970 +0000
573 summary: b1.1
573 summary: b1.1
574
574
575 diff --git a/b1 b/b1
575 diff --git a/b1 b/b1
576 --- a/b1
576 --- a/b1
577 +++ b/b1
577 +++ b/b1
578 @@ -1,1 +1,2 @@
578 @@ -1,1 +1,2 @@
579 b1
579 b1
580 +postm
580 +postm
581
581
582
582
583
583
584 log -r ""
584 log -r ""
585
585
586 $ hg log -r ''
586 $ hg log -r ''
587 hg: parse error: empty query
587 hg: parse error: empty query
588 [255]
588 [255]
589
589
590 log -r <some unknown node id>
590 log -r <some unknown node id>
591
591
592 $ hg log -r 1000000000000000000000000000000000000000
592 $ hg log -r 1000000000000000000000000000000000000000
593 abort: unknown revision '1000000000000000000000000000000000000000'!
593 abort: unknown revision '1000000000000000000000000000000000000000'!
594 [255]
594 [255]
595
595
596 log -k r1
596 log -k r1
597
597
598 $ hg log -k r1
598 $ hg log -k r1
599 changeset: 1:3d5bf5654eda
599 changeset: 1:3d5bf5654eda
600 user: test
600 user: test
601 date: Thu Jan 01 00:00:01 1970 +0000
601 date: Thu Jan 01 00:00:01 1970 +0000
602 summary: r1
602 summary: r1
603
603
604 log -p -l2 --color=always
604 log -p -l2 --color=always
605
605
606 $ hg --config extensions.color= --config color.mode=ansi \
606 $ hg --config extensions.color= --config color.mode=ansi \
607 > log -p -l2 --color=always
607 > log -p -l2 --color=always
608 \x1b[0;33mchangeset: 6:2404bbcab562\x1b[0m (esc)
608 \x1b[0;33mchangeset: 6:2404bbcab562\x1b[0m (esc)
609 tag: tip
609 tag: tip
610 user: test
610 user: test
611 date: Thu Jan 01 00:00:01 1970 +0000
611 date: Thu Jan 01 00:00:01 1970 +0000
612 summary: b1.1
612 summary: b1.1
613
613
614 \x1b[0;1mdiff -r 302e9dd6890d -r 2404bbcab562 b1\x1b[0m (esc)
614 \x1b[0;1mdiff -r 302e9dd6890d -r 2404bbcab562 b1\x1b[0m (esc)
615 \x1b[0;31;1m--- a/b1 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
615 \x1b[0;31;1m--- a/b1 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
616 \x1b[0;32;1m+++ b/b1 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
616 \x1b[0;32;1m+++ b/b1 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
617 \x1b[0;35m@@ -1,1 +1,2 @@\x1b[0m (esc)
617 \x1b[0;35m@@ -1,1 +1,2 @@\x1b[0m (esc)
618 b1
618 b1
619 \x1b[0;32m+postm\x1b[0m (esc)
619 \x1b[0;32m+postm\x1b[0m (esc)
620
620
621 \x1b[0;33mchangeset: 5:302e9dd6890d\x1b[0m (esc)
621 \x1b[0;33mchangeset: 5:302e9dd6890d\x1b[0m (esc)
622 parent: 3:e62f78d544b4
622 parent: 3:e62f78d544b4
623 parent: 4:ddb82e70d1a1
623 parent: 4:ddb82e70d1a1
624 user: test
624 user: test
625 date: Thu Jan 01 00:00:01 1970 +0000
625 date: Thu Jan 01 00:00:01 1970 +0000
626 summary: m12
626 summary: m12
627
627
628 \x1b[0;1mdiff -r e62f78d544b4 -r 302e9dd6890d b2\x1b[0m (esc)
628 \x1b[0;1mdiff -r e62f78d544b4 -r 302e9dd6890d b2\x1b[0m (esc)
629 \x1b[0;31;1m--- /dev/null Thu Jan 01 00:00:00 1970 +0000\x1b[0m (esc)
629 \x1b[0;31;1m--- /dev/null Thu Jan 01 00:00:00 1970 +0000\x1b[0m (esc)
630 \x1b[0;32;1m+++ b/b2 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
630 \x1b[0;32;1m+++ b/b2 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
631 \x1b[0;35m@@ -0,0 +1,1 @@\x1b[0m (esc)
631 \x1b[0;35m@@ -0,0 +1,1 @@\x1b[0m (esc)
632 \x1b[0;32m+b2\x1b[0m (esc)
632 \x1b[0;32m+b2\x1b[0m (esc)
633
633
634
634
635
635
636 log -r tip --stat
636 log -r tip --stat
637
637
638 $ hg log -r tip --stat
638 $ hg log -r tip --stat
639 changeset: 6:2404bbcab562
639 changeset: 6:2404bbcab562
640 tag: tip
640 tag: tip
641 user: test
641 user: test
642 date: Thu Jan 01 00:00:01 1970 +0000
642 date: Thu Jan 01 00:00:01 1970 +0000
643 summary: b1.1
643 summary: b1.1
644
644
645 b1 | 1 +
645 b1 | 1 +
646 1 files changed, 1 insertions(+), 0 deletions(-)
646 1 files changed, 1 insertions(+), 0 deletions(-)
647
647
648
648
649 $ cd ..
649 $ cd ..
650
650
651
651
652 User
652 User
653
653
654 $ hg init usertest
654 $ hg init usertest
655 $ cd usertest
655 $ cd usertest
656
656
657 $ echo a > a
657 $ echo a > a
658 $ hg ci -A -m "a" -u "User One <user1@example.org>"
658 $ hg ci -A -m "a" -u "User One <user1@example.org>"
659 adding a
659 adding a
660 $ echo b > b
660 $ echo b > b
661 $ hg ci -A -m "b" -u "User Two <user2@example.org>"
661 $ hg ci -A -m "b" -u "User Two <user2@example.org>"
662 adding b
662 adding b
663
663
664 $ hg log -u "User One <user1@example.org>"
664 $ hg log -u "User One <user1@example.org>"
665 changeset: 0:29a4c94f1924
665 changeset: 0:29a4c94f1924
666 user: User One <user1@example.org>
666 user: User One <user1@example.org>
667 date: Thu Jan 01 00:00:00 1970 +0000
667 date: Thu Jan 01 00:00:00 1970 +0000
668 summary: a
668 summary: a
669
669
670 $ hg log -u "user1" -u "user2"
670 $ hg log -u "user1" -u "user2"
671 changeset: 1:e834b5e69c0e
671 changeset: 1:e834b5e69c0e
672 tag: tip
672 tag: tip
673 user: User Two <user2@example.org>
673 user: User Two <user2@example.org>
674 date: Thu Jan 01 00:00:00 1970 +0000
674 date: Thu Jan 01 00:00:00 1970 +0000
675 summary: b
675 summary: b
676
676
677 changeset: 0:29a4c94f1924
677 changeset: 0:29a4c94f1924
678 user: User One <user1@example.org>
678 user: User One <user1@example.org>
679 date: Thu Jan 01 00:00:00 1970 +0000
679 date: Thu Jan 01 00:00:00 1970 +0000
680 summary: a
680 summary: a
681
681
682 $ hg log -u "user3"
682 $ hg log -u "user3"
683
683
684 $ cd ..
684 $ cd ..
685
685
686 $ hg init branches
686 $ hg init branches
687 $ cd branches
687 $ cd branches
688
688
689 $ echo a > a
689 $ echo a > a
690 $ hg ci -A -m "commit on default"
690 $ hg ci -A -m "commit on default"
691 adding a
691 adding a
692 $ hg branch test
692 $ hg branch test
693 marked working directory as branch test
693 marked working directory as branch test
694 (branches are permanent and global, did you want a bookmark?)
694 (branches are permanent and global, did you want a bookmark?)
695 $ echo b > b
695 $ echo b > b
696 $ hg ci -A -m "commit on test"
696 $ hg ci -A -m "commit on test"
697 adding b
697 adding b
698
698
699 $ hg up default
699 $ hg up default
700 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
700 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
701 $ echo c > c
701 $ echo c > c
702 $ hg ci -A -m "commit on default"
702 $ hg ci -A -m "commit on default"
703 adding c
703 adding c
704 $ hg up test
704 $ hg up test
705 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
705 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
706 $ echo c > c
706 $ echo c > c
707 $ hg ci -A -m "commit on test"
707 $ hg ci -A -m "commit on test"
708 adding c
708 adding c
709
709
710
710
711 log -b default
711 log -b default
712
712
713 $ hg log -b default
713 $ hg log -b default
714 changeset: 2:c3a4f03cc9a7
714 changeset: 2:c3a4f03cc9a7
715 parent: 0:24427303d56f
715 parent: 0:24427303d56f
716 user: test
716 user: test
717 date: Thu Jan 01 00:00:00 1970 +0000
717 date: Thu Jan 01 00:00:00 1970 +0000
718 summary: commit on default
718 summary: commit on default
719
719
720 changeset: 0:24427303d56f
720 changeset: 0:24427303d56f
721 user: test
721 user: test
722 date: Thu Jan 01 00:00:00 1970 +0000
722 date: Thu Jan 01 00:00:00 1970 +0000
723 summary: commit on default
723 summary: commit on default
724
724
725
725
726
726
727 log -b test
727 log -b test
728
728
729 $ hg log -b test
729 $ hg log -b test
730 changeset: 3:f5d8de11c2e2
730 changeset: 3:f5d8de11c2e2
731 branch: test
731 branch: test
732 tag: tip
732 tag: tip
733 parent: 1:d32277701ccb
733 parent: 1:d32277701ccb
734 user: test
734 user: test
735 date: Thu Jan 01 00:00:00 1970 +0000
735 date: Thu Jan 01 00:00:00 1970 +0000
736 summary: commit on test
736 summary: commit on test
737
737
738 changeset: 1:d32277701ccb
738 changeset: 1:d32277701ccb
739 branch: test
739 branch: test
740 user: test
740 user: test
741 date: Thu Jan 01 00:00:00 1970 +0000
741 date: Thu Jan 01 00:00:00 1970 +0000
742 summary: commit on test
742 summary: commit on test
743
743
744
744
745
745
746 log -b dummy
746 log -b dummy
747
747
748 $ hg log -b dummy
748 $ hg log -b dummy
749 abort: unknown revision 'dummy'!
749 abort: unknown revision 'dummy'!
750 [255]
750 [255]
751
751
752
752
753 log -b .
753 log -b .
754
754
755 $ hg log -b .
755 $ hg log -b .
756 changeset: 3:f5d8de11c2e2
756 changeset: 3:f5d8de11c2e2
757 branch: test
757 branch: test
758 tag: tip
758 tag: tip
759 parent: 1:d32277701ccb
759 parent: 1:d32277701ccb
760 user: test
760 user: test
761 date: Thu Jan 01 00:00:00 1970 +0000
761 date: Thu Jan 01 00:00:00 1970 +0000
762 summary: commit on test
762 summary: commit on test
763
763
764 changeset: 1:d32277701ccb
764 changeset: 1:d32277701ccb
765 branch: test
765 branch: test
766 user: test
766 user: test
767 date: Thu Jan 01 00:00:00 1970 +0000
767 date: Thu Jan 01 00:00:00 1970 +0000
768 summary: commit on test
768 summary: commit on test
769
769
770
770
771
771
772 log -b default -b test
772 log -b default -b test
773
773
774 $ hg log -b default -b test
774 $ hg log -b default -b test
775 changeset: 3:f5d8de11c2e2
775 changeset: 3:f5d8de11c2e2
776 branch: test
776 branch: test
777 tag: tip
777 tag: tip
778 parent: 1:d32277701ccb
778 parent: 1:d32277701ccb
779 user: test
779 user: test
780 date: Thu Jan 01 00:00:00 1970 +0000
780 date: Thu Jan 01 00:00:00 1970 +0000
781 summary: commit on test
781 summary: commit on test
782
782
783 changeset: 2:c3a4f03cc9a7
783 changeset: 2:c3a4f03cc9a7
784 parent: 0:24427303d56f
784 parent: 0:24427303d56f
785 user: test
785 user: test
786 date: Thu Jan 01 00:00:00 1970 +0000
786 date: Thu Jan 01 00:00:00 1970 +0000
787 summary: commit on default
787 summary: commit on default
788
788
789 changeset: 1:d32277701ccb
789 changeset: 1:d32277701ccb
790 branch: test
790 branch: test
791 user: test
791 user: test
792 date: Thu Jan 01 00:00:00 1970 +0000
792 date: Thu Jan 01 00:00:00 1970 +0000
793 summary: commit on test
793 summary: commit on test
794
794
795 changeset: 0:24427303d56f
795 changeset: 0:24427303d56f
796 user: test
796 user: test
797 date: Thu Jan 01 00:00:00 1970 +0000
797 date: Thu Jan 01 00:00:00 1970 +0000
798 summary: commit on default
798 summary: commit on default
799
799
800
800
801
801
802 log -b default -b .
802 log -b default -b .
803
803
804 $ hg log -b default -b .
804 $ hg log -b default -b .
805 changeset: 3:f5d8de11c2e2
805 changeset: 3:f5d8de11c2e2
806 branch: test
806 branch: test
807 tag: tip
807 tag: tip
808 parent: 1:d32277701ccb
808 parent: 1:d32277701ccb
809 user: test
809 user: test
810 date: Thu Jan 01 00:00:00 1970 +0000
810 date: Thu Jan 01 00:00:00 1970 +0000
811 summary: commit on test
811 summary: commit on test
812
812
813 changeset: 2:c3a4f03cc9a7
813 changeset: 2:c3a4f03cc9a7
814 parent: 0:24427303d56f
814 parent: 0:24427303d56f
815 user: test
815 user: test
816 date: Thu Jan 01 00:00:00 1970 +0000
816 date: Thu Jan 01 00:00:00 1970 +0000
817 summary: commit on default
817 summary: commit on default
818
818
819 changeset: 1:d32277701ccb
819 changeset: 1:d32277701ccb
820 branch: test
820 branch: test
821 user: test
821 user: test
822 date: Thu Jan 01 00:00:00 1970 +0000
822 date: Thu Jan 01 00:00:00 1970 +0000
823 summary: commit on test
823 summary: commit on test
824
824
825 changeset: 0:24427303d56f
825 changeset: 0:24427303d56f
826 user: test
826 user: test
827 date: Thu Jan 01 00:00:00 1970 +0000
827 date: Thu Jan 01 00:00:00 1970 +0000
828 summary: commit on default
828 summary: commit on default
829
829
830
830
831
831
832 log -b . -b test
832 log -b . -b test
833
833
834 $ hg log -b . -b test
834 $ hg log -b . -b test
835 changeset: 3:f5d8de11c2e2
835 changeset: 3:f5d8de11c2e2
836 branch: test
836 branch: test
837 tag: tip
837 tag: tip
838 parent: 1:d32277701ccb
838 parent: 1:d32277701ccb
839 user: test
839 user: test
840 date: Thu Jan 01 00:00:00 1970 +0000
840 date: Thu Jan 01 00:00:00 1970 +0000
841 summary: commit on test
841 summary: commit on test
842
842
843 changeset: 1:d32277701ccb
843 changeset: 1:d32277701ccb
844 branch: test
844 branch: test
845 user: test
845 user: test
846 date: Thu Jan 01 00:00:00 1970 +0000
846 date: Thu Jan 01 00:00:00 1970 +0000
847 summary: commit on test
847 summary: commit on test
848
848
849
849
850
850
851 log -b 2
851 log -b 2
852
852
853 $ hg log -b 2
853 $ hg log -b 2
854 changeset: 2:c3a4f03cc9a7
854 changeset: 2:c3a4f03cc9a7
855 parent: 0:24427303d56f
855 parent: 0:24427303d56f
856 user: test
856 user: test
857 date: Thu Jan 01 00:00:00 1970 +0000
857 date: Thu Jan 01 00:00:00 1970 +0000
858 summary: commit on default
858 summary: commit on default
859
859
860 changeset: 0:24427303d56f
860 changeset: 0:24427303d56f
861 user: test
861 user: test
862 date: Thu Jan 01 00:00:00 1970 +0000
862 date: Thu Jan 01 00:00:00 1970 +0000
863 summary: commit on default
863 summary: commit on default
864
864
865
865
866
866
867 log -p --cwd dir (in subdir)
867 log -p --cwd dir (in subdir)
868
868
869 $ mkdir dir
869 $ mkdir dir
870 $ hg log -p --cwd dir
870 $ hg log -p --cwd dir
871 changeset: 3:f5d8de11c2e2
871 changeset: 3:f5d8de11c2e2
872 branch: test
872 branch: test
873 tag: tip
873 tag: tip
874 parent: 1:d32277701ccb
874 parent: 1:d32277701ccb
875 user: test
875 user: test
876 date: Thu Jan 01 00:00:00 1970 +0000
876 date: Thu Jan 01 00:00:00 1970 +0000
877 summary: commit on test
877 summary: commit on test
878
878
879 diff -r d32277701ccb -r f5d8de11c2e2 c
879 diff -r d32277701ccb -r f5d8de11c2e2 c
880 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
880 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
881 +++ b/c Thu Jan 01 00:00:00 1970 +0000
881 +++ b/c Thu Jan 01 00:00:00 1970 +0000
882 @@ -0,0 +1,1 @@
882 @@ -0,0 +1,1 @@
883 +c
883 +c
884
884
885 changeset: 2:c3a4f03cc9a7
885 changeset: 2:c3a4f03cc9a7
886 parent: 0:24427303d56f
886 parent: 0:24427303d56f
887 user: test
887 user: test
888 date: Thu Jan 01 00:00:00 1970 +0000
888 date: Thu Jan 01 00:00:00 1970 +0000
889 summary: commit on default
889 summary: commit on default
890
890
891 diff -r 24427303d56f -r c3a4f03cc9a7 c
891 diff -r 24427303d56f -r c3a4f03cc9a7 c
892 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
892 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
893 +++ b/c Thu Jan 01 00:00:00 1970 +0000
893 +++ b/c Thu Jan 01 00:00:00 1970 +0000
894 @@ -0,0 +1,1 @@
894 @@ -0,0 +1,1 @@
895 +c
895 +c
896
896
897 changeset: 1:d32277701ccb
897 changeset: 1:d32277701ccb
898 branch: test
898 branch: test
899 user: test
899 user: test
900 date: Thu Jan 01 00:00:00 1970 +0000
900 date: Thu Jan 01 00:00:00 1970 +0000
901 summary: commit on test
901 summary: commit on test
902
902
903 diff -r 24427303d56f -r d32277701ccb b
903 diff -r 24427303d56f -r d32277701ccb b
904 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
904 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
905 +++ b/b Thu Jan 01 00:00:00 1970 +0000
905 +++ b/b Thu Jan 01 00:00:00 1970 +0000
906 @@ -0,0 +1,1 @@
906 @@ -0,0 +1,1 @@
907 +b
907 +b
908
908
909 changeset: 0:24427303d56f
909 changeset: 0:24427303d56f
910 user: test
910 user: test
911 date: Thu Jan 01 00:00:00 1970 +0000
911 date: Thu Jan 01 00:00:00 1970 +0000
912 summary: commit on default
912 summary: commit on default
913
913
914 diff -r 000000000000 -r 24427303d56f a
914 diff -r 000000000000 -r 24427303d56f a
915 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
915 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
916 +++ b/a Thu Jan 01 00:00:00 1970 +0000
916 +++ b/a Thu Jan 01 00:00:00 1970 +0000
917 @@ -0,0 +1,1 @@
917 @@ -0,0 +1,1 @@
918 +a
918 +a
919
919
920
920
921
921
922 log -p -R repo
922 log -p -R repo
923
923
924 $ cd dir
924 $ cd dir
925 $ hg log -p -R .. ../a
925 $ hg log -p -R .. ../a
926 changeset: 0:24427303d56f
926 changeset: 0:24427303d56f
927 user: test
927 user: test
928 date: Thu Jan 01 00:00:00 1970 +0000
928 date: Thu Jan 01 00:00:00 1970 +0000
929 summary: commit on default
929 summary: commit on default
930
930
931 diff -r 000000000000 -r 24427303d56f a
931 diff -r 000000000000 -r 24427303d56f a
932 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
932 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
933 +++ b/a Thu Jan 01 00:00:00 1970 +0000
933 +++ b/a Thu Jan 01 00:00:00 1970 +0000
934 @@ -0,0 +1,1 @@
934 @@ -0,0 +1,1 @@
935 +a
935 +a
936
936
937
937
938 $ cd ../..
938 $ cd ../..
939
939
940 $ hg init follow2
940 $ hg init follow2
941 $ cd follow2
941 $ cd follow2
942
942
943 # Build the following history:
943 # Build the following history:
944 # tip - o - x - o - x - x
944 # tip - o - x - o - x - x
945 # \ /
945 # \ /
946 # o - o - o - x
946 # o - o - o - x
947 # \ /
947 # \ /
948 # o
948 # o
949 #
949 #
950 # Where "o" is a revision containing "foo" and
950 # Where "o" is a revision containing "foo" and
951 # "x" is a revision without "foo"
951 # "x" is a revision without "foo"
952
952
953 $ touch init
953 $ touch init
954 $ hg ci -A -m "init, unrelated"
954 $ hg ci -A -m "init, unrelated"
955 adding init
955 adding init
956 $ echo 'foo' > init
956 $ echo 'foo' > init
957 $ hg ci -m "change, unrelated"
957 $ hg ci -m "change, unrelated"
958 $ echo 'foo' > foo
958 $ echo 'foo' > foo
959 $ hg ci -A -m "add unrelated old foo"
959 $ hg ci -A -m "add unrelated old foo"
960 adding foo
960 adding foo
961 $ hg rm foo
961 $ hg rm foo
962 $ hg ci -m "delete foo, unrelated"
962 $ hg ci -m "delete foo, unrelated"
963 $ echo 'related' > foo
963 $ echo 'related' > foo
964 $ hg ci -A -m "add foo, related"
964 $ hg ci -A -m "add foo, related"
965 adding foo
965 adding foo
966
966
967 $ hg up 0
967 $ hg up 0
968 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
968 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
969 $ touch branch
969 $ touch branch
970 $ hg ci -A -m "first branch, unrelated"
970 $ hg ci -A -m "first branch, unrelated"
971 adding branch
971 adding branch
972 created new head
972 created new head
973 $ touch foo
973 $ touch foo
974 $ hg ci -A -m "create foo, related"
974 $ hg ci -A -m "create foo, related"
975 adding foo
975 adding foo
976 $ echo 'change' > foo
976 $ echo 'change' > foo
977 $ hg ci -m "change foo, related"
977 $ hg ci -m "change foo, related"
978
978
979 $ hg up 6
979 $ hg up 6
980 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
980 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
981 $ echo 'change foo in branch' > foo
981 $ echo 'change foo in branch' > foo
982 $ hg ci -m "change foo in branch, related"
982 $ hg ci -m "change foo in branch, related"
983 created new head
983 created new head
984 $ hg merge 7
984 $ hg merge 7
985 merging foo
985 merging foo
986 warning: conflicts during merge.
986 warning: conflicts during merge.
987 merging foo incomplete! (edit conflicts, then use 'hg resolve --mark')
987 merging foo incomplete! (edit conflicts, then use 'hg resolve --mark')
988 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
988 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
989 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
989 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
990 [1]
990 [1]
991 $ echo 'merge 1' > foo
991 $ echo 'merge 1' > foo
992 $ hg resolve -m foo
992 $ hg resolve -m foo
993 $ hg ci -m "First merge, related"
993 $ hg ci -m "First merge, related"
994
994
995 $ hg merge 4
995 $ hg merge 4
996 merging foo
996 merging foo
997 warning: conflicts during merge.
997 warning: conflicts during merge.
998 merging foo incomplete! (edit conflicts, then use 'hg resolve --mark')
998 merging foo incomplete! (edit conflicts, then use 'hg resolve --mark')
999 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
999 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
1000 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
1000 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
1001 [1]
1001 [1]
1002 $ echo 'merge 2' > foo
1002 $ echo 'merge 2' > foo
1003 $ hg resolve -m foo
1003 $ hg resolve -m foo
1004 $ hg ci -m "Last merge, related"
1004 $ hg ci -m "Last merge, related"
1005
1005
1006 $ hg log --graph
1006 $ hg log --graph
1007 @ changeset: 10:4dae8563d2c5
1007 @ changeset: 10:4dae8563d2c5
1008 |\ tag: tip
1008 |\ tag: tip
1009 | | parent: 9:7b35701b003e
1009 | | parent: 9:7b35701b003e
1010 | | parent: 4:88176d361b69
1010 | | parent: 4:88176d361b69
1011 | | user: test
1011 | | user: test
1012 | | date: Thu Jan 01 00:00:00 1970 +0000
1012 | | date: Thu Jan 01 00:00:00 1970 +0000
1013 | | summary: Last merge, related
1013 | | summary: Last merge, related
1014 | |
1014 | |
1015 | o changeset: 9:7b35701b003e
1015 | o changeset: 9:7b35701b003e
1016 | |\ parent: 8:e5416ad8a855
1016 | |\ parent: 8:e5416ad8a855
1017 | | | parent: 7:87fe3144dcfa
1017 | | | parent: 7:87fe3144dcfa
1018 | | | user: test
1018 | | | user: test
1019 | | | date: Thu Jan 01 00:00:00 1970 +0000
1019 | | | date: Thu Jan 01 00:00:00 1970 +0000
1020 | | | summary: First merge, related
1020 | | | summary: First merge, related
1021 | | |
1021 | | |
1022 | | o changeset: 8:e5416ad8a855
1022 | | o changeset: 8:e5416ad8a855
1023 | | | parent: 6:dc6c325fe5ee
1023 | | | parent: 6:dc6c325fe5ee
1024 | | | user: test
1024 | | | user: test
1025 | | | date: Thu Jan 01 00:00:00 1970 +0000
1025 | | | date: Thu Jan 01 00:00:00 1970 +0000
1026 | | | summary: change foo in branch, related
1026 | | | summary: change foo in branch, related
1027 | | |
1027 | | |
1028 | o | changeset: 7:87fe3144dcfa
1028 | o | changeset: 7:87fe3144dcfa
1029 | |/ user: test
1029 | |/ user: test
1030 | | date: Thu Jan 01 00:00:00 1970 +0000
1030 | | date: Thu Jan 01 00:00:00 1970 +0000
1031 | | summary: change foo, related
1031 | | summary: change foo, related
1032 | |
1032 | |
1033 | o changeset: 6:dc6c325fe5ee
1033 | o changeset: 6:dc6c325fe5ee
1034 | | user: test
1034 | | user: test
1035 | | date: Thu Jan 01 00:00:00 1970 +0000
1035 | | date: Thu Jan 01 00:00:00 1970 +0000
1036 | | summary: create foo, related
1036 | | summary: create foo, related
1037 | |
1037 | |
1038 | o changeset: 5:73db34516eb9
1038 | o changeset: 5:73db34516eb9
1039 | | parent: 0:e87515fd044a
1039 | | parent: 0:e87515fd044a
1040 | | user: test
1040 | | user: test
1041 | | date: Thu Jan 01 00:00:00 1970 +0000
1041 | | date: Thu Jan 01 00:00:00 1970 +0000
1042 | | summary: first branch, unrelated
1042 | | summary: first branch, unrelated
1043 | |
1043 | |
1044 o | changeset: 4:88176d361b69
1044 o | changeset: 4:88176d361b69
1045 | | user: test
1045 | | user: test
1046 | | date: Thu Jan 01 00:00:00 1970 +0000
1046 | | date: Thu Jan 01 00:00:00 1970 +0000
1047 | | summary: add foo, related
1047 | | summary: add foo, related
1048 | |
1048 | |
1049 o | changeset: 3:dd78ae4afb56
1049 o | changeset: 3:dd78ae4afb56
1050 | | user: test
1050 | | user: test
1051 | | date: Thu Jan 01 00:00:00 1970 +0000
1051 | | date: Thu Jan 01 00:00:00 1970 +0000
1052 | | summary: delete foo, unrelated
1052 | | summary: delete foo, unrelated
1053 | |
1053 | |
1054 o | changeset: 2:c4c64aedf0f7
1054 o | changeset: 2:c4c64aedf0f7
1055 | | user: test
1055 | | user: test
1056 | | date: Thu Jan 01 00:00:00 1970 +0000
1056 | | date: Thu Jan 01 00:00:00 1970 +0000
1057 | | summary: add unrelated old foo
1057 | | summary: add unrelated old foo
1058 | |
1058 | |
1059 o | changeset: 1:e5faa7440653
1059 o | changeset: 1:e5faa7440653
1060 |/ user: test
1060 |/ user: test
1061 | date: Thu Jan 01 00:00:00 1970 +0000
1061 | date: Thu Jan 01 00:00:00 1970 +0000
1062 | summary: change, unrelated
1062 | summary: change, unrelated
1063 |
1063 |
1064 o changeset: 0:e87515fd044a
1064 o changeset: 0:e87515fd044a
1065 user: test
1065 user: test
1066 date: Thu Jan 01 00:00:00 1970 +0000
1066 date: Thu Jan 01 00:00:00 1970 +0000
1067 summary: init, unrelated
1067 summary: init, unrelated
1068
1068
1069
1069
1070 $ hg --traceback log -f foo
1070 $ hg --traceback log -f foo
1071 changeset: 10:4dae8563d2c5
1071 changeset: 10:4dae8563d2c5
1072 tag: tip
1072 tag: tip
1073 parent: 9:7b35701b003e
1073 parent: 9:7b35701b003e
1074 parent: 4:88176d361b69
1074 parent: 4:88176d361b69
1075 user: test
1075 user: test
1076 date: Thu Jan 01 00:00:00 1970 +0000
1076 date: Thu Jan 01 00:00:00 1970 +0000
1077 summary: Last merge, related
1077 summary: Last merge, related
1078
1078
1079 changeset: 9:7b35701b003e
1079 changeset: 9:7b35701b003e
1080 parent: 8:e5416ad8a855
1080 parent: 8:e5416ad8a855
1081 parent: 7:87fe3144dcfa
1081 parent: 7:87fe3144dcfa
1082 user: test
1082 user: test
1083 date: Thu Jan 01 00:00:00 1970 +0000
1083 date: Thu Jan 01 00:00:00 1970 +0000
1084 summary: First merge, related
1084 summary: First merge, related
1085
1085
1086 changeset: 8:e5416ad8a855
1086 changeset: 8:e5416ad8a855
1087 parent: 6:dc6c325fe5ee
1087 parent: 6:dc6c325fe5ee
1088 user: test
1088 user: test
1089 date: Thu Jan 01 00:00:00 1970 +0000
1089 date: Thu Jan 01 00:00:00 1970 +0000
1090 summary: change foo in branch, related
1090 summary: change foo in branch, related
1091
1091
1092 changeset: 7:87fe3144dcfa
1092 changeset: 7:87fe3144dcfa
1093 user: test
1093 user: test
1094 date: Thu Jan 01 00:00:00 1970 +0000
1094 date: Thu Jan 01 00:00:00 1970 +0000
1095 summary: change foo, related
1095 summary: change foo, related
1096
1096
1097 changeset: 6:dc6c325fe5ee
1097 changeset: 6:dc6c325fe5ee
1098 user: test
1098 user: test
1099 date: Thu Jan 01 00:00:00 1970 +0000
1099 date: Thu Jan 01 00:00:00 1970 +0000
1100 summary: create foo, related
1100 summary: create foo, related
1101
1101
1102 changeset: 4:88176d361b69
1102 changeset: 4:88176d361b69
1103 user: test
1103 user: test
1104 date: Thu Jan 01 00:00:00 1970 +0000
1104 date: Thu Jan 01 00:00:00 1970 +0000
1105 summary: add foo, related
1105 summary: add foo, related
1106
1106
1107
1107
1108 Also check when maxrev < lastrevfilelog
1108 Also check when maxrev < lastrevfilelog
1109
1109
1110 $ hg --traceback log -f -r4 foo
1110 $ hg --traceback log -f -r4 foo
1111 changeset: 4:88176d361b69
1111 changeset: 4:88176d361b69
1112 user: test
1112 user: test
1113 date: Thu Jan 01 00:00:00 1970 +0000
1113 date: Thu Jan 01 00:00:00 1970 +0000
1114 summary: add foo, related
1114 summary: add foo, related
1115
1115
1116 $ cd ..
1116 $ cd ..
1117
1117
1118 Issue2383: hg log showing _less_ differences than hg diff
1118 Issue2383: hg log showing _less_ differences than hg diff
1119
1119
1120 $ hg init issue2383
1120 $ hg init issue2383
1121 $ cd issue2383
1121 $ cd issue2383
1122
1122
1123 Create a test repo:
1123 Create a test repo:
1124
1124
1125 $ echo a > a
1125 $ echo a > a
1126 $ hg ci -Am0
1126 $ hg ci -Am0
1127 adding a
1127 adding a
1128 $ echo b > b
1128 $ echo b > b
1129 $ hg ci -Am1
1129 $ hg ci -Am1
1130 adding b
1130 adding b
1131 $ hg co 0
1131 $ hg co 0
1132 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1132 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1133 $ echo b > a
1133 $ echo b > a
1134 $ hg ci -m2
1134 $ hg ci -m2
1135 created new head
1135 created new head
1136
1136
1137 Merge:
1137 Merge:
1138
1138
1139 $ hg merge
1139 $ hg merge
1140 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1140 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1141 (branch merge, don't forget to commit)
1141 (branch merge, don't forget to commit)
1142
1142
1143 Make sure there's a file listed in the merge to trigger the bug:
1143 Make sure there's a file listed in the merge to trigger the bug:
1144
1144
1145 $ echo c > a
1145 $ echo c > a
1146 $ hg ci -m3
1146 $ hg ci -m3
1147
1147
1148 Two files shown here in diff:
1148 Two files shown here in diff:
1149
1149
1150 $ hg diff --rev 2:3
1150 $ hg diff --rev 2:3
1151 diff -r b09be438c43a -r 8e07aafe1edc a
1151 diff -r b09be438c43a -r 8e07aafe1edc a
1152 --- a/a Thu Jan 01 00:00:00 1970 +0000
1152 --- a/a Thu Jan 01 00:00:00 1970 +0000
1153 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1153 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1154 @@ -1,1 +1,1 @@
1154 @@ -1,1 +1,1 @@
1155 -b
1155 -b
1156 +c
1156 +c
1157 diff -r b09be438c43a -r 8e07aafe1edc b
1157 diff -r b09be438c43a -r 8e07aafe1edc b
1158 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1158 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1159 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1159 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1160 @@ -0,0 +1,1 @@
1160 @@ -0,0 +1,1 @@
1161 +b
1161 +b
1162
1162
1163 Diff here should be the same:
1163 Diff here should be the same:
1164
1164
1165 $ hg log -vpr 3
1165 $ hg log -vpr 3
1166 changeset: 3:8e07aafe1edc
1166 changeset: 3:8e07aafe1edc
1167 tag: tip
1167 tag: tip
1168 parent: 2:b09be438c43a
1168 parent: 2:b09be438c43a
1169 parent: 1:925d80f479bb
1169 parent: 1:925d80f479bb
1170 user: test
1170 user: test
1171 date: Thu Jan 01 00:00:00 1970 +0000
1171 date: Thu Jan 01 00:00:00 1970 +0000
1172 files: a
1172 files: a
1173 description:
1173 description:
1174 3
1174 3
1175
1175
1176
1176
1177 diff -r b09be438c43a -r 8e07aafe1edc a
1177 diff -r b09be438c43a -r 8e07aafe1edc a
1178 --- a/a Thu Jan 01 00:00:00 1970 +0000
1178 --- a/a Thu Jan 01 00:00:00 1970 +0000
1179 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1179 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1180 @@ -1,1 +1,1 @@
1180 @@ -1,1 +1,1 @@
1181 -b
1181 -b
1182 +c
1182 +c
1183 diff -r b09be438c43a -r 8e07aafe1edc b
1183 diff -r b09be438c43a -r 8e07aafe1edc b
1184 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1184 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1185 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1185 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1186 @@ -0,0 +1,1 @@
1186 @@ -0,0 +1,1 @@
1187 +b
1187 +b
1188
1188
1189 $ cd ..
1189 $ cd ..
1190
1190
1191 'hg log -r rev fn' when last(filelog(fn)) != rev
1191 'hg log -r rev fn' when last(filelog(fn)) != rev
1192
1192
1193 $ hg init simplelog
1193 $ hg init simplelog
1194 $ cd simplelog
1194 $ cd simplelog
1195 $ echo f > a
1195 $ echo f > a
1196 $ hg ci -Am'a' -d '0 0'
1196 $ hg ci -Am'a' -d '0 0'
1197 adding a
1197 adding a
1198 $ echo f >> a
1198 $ echo f >> a
1199 $ hg ci -Am'a bis' -d '1 0'
1199 $ hg ci -Am'a bis' -d '1 0'
1200
1200
1201 $ hg log -r0 a
1201 $ hg log -r0 a
1202 changeset: 0:9f758d63dcde
1202 changeset: 0:9f758d63dcde
1203 user: test
1203 user: test
1204 date: Thu Jan 01 00:00:00 1970 +0000
1204 date: Thu Jan 01 00:00:00 1970 +0000
1205 summary: a
1205 summary: a
1206
1206
1207 enable obsolete to test hidden feature
1207 enable obsolete to test hidden feature
1208
1208
1209 $ cat > ${TESTTMP}/obs.py << EOF
1209 $ cat > ${TESTTMP}/obs.py << EOF
1210 > import mercurial.obsolete
1210 > import mercurial.obsolete
1211 > mercurial.obsolete._enabled = True
1211 > mercurial.obsolete._enabled = True
1212 > EOF
1212 > EOF
1213 $ echo '[extensions]' >> $HGRCPATH
1213 $ echo '[extensions]' >> $HGRCPATH
1214 $ echo "obs=${TESTTMP}/obs.py" >> $HGRCPATH
1214 $ echo "obs=${TESTTMP}/obs.py" >> $HGRCPATH
1215
1215
1216 $ hg log --template='{rev}:{node}\n'
1216 $ hg log --template='{rev}:{node}\n'
1217 1:a765632148dc55d38c35c4f247c618701886cb2f
1217 1:a765632148dc55d38c35c4f247c618701886cb2f
1218 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1218 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1219 $ hg debugobsolete a765632148dc55d38c35c4f247c618701886cb2f
1219 $ hg debugobsolete a765632148dc55d38c35c4f247c618701886cb2f
1220 $ hg up null -q
1220 $ hg up null -q
1221 $ hg log --template='{rev}:{node}\n'
1221 $ hg log --template='{rev}:{node}\n'
1222 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1222 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1223 $ hg log --template='{rev}:{node}\n' --hidden
1223 $ hg log --template='{rev}:{node}\n' --hidden
1224 1:a765632148dc55d38c35c4f247c618701886cb2f
1224 1:a765632148dc55d38c35c4f247c618701886cb2f
1225 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1225 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1226 $ hg log -r a
1226 $ hg log -r a
1227 abort: unknown revision 'a'!
1227 abort: unknown revision 'a'!
1228 [255]
1228 [255]
1229
1229
1230 test that parent prevent a changeset to be hidden
1230 test that parent prevent a changeset to be hidden
1231
1231
1232 $ hg up 1 -q --hidden
1232 $ hg up 1 -q --hidden
1233 $ hg log --template='{rev}:{node}\n'
1233 $ hg log --template='{rev}:{node}\n'
1234 1:a765632148dc55d38c35c4f247c618701886cb2f
1234 1:a765632148dc55d38c35c4f247c618701886cb2f
1235 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1235 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1236
1236
1237 test that second parent prevent a changeset to be hidden too
1237 test that second parent prevent a changeset to be hidden too
1238
1238
1239 $ hg debugsetparents 0 1 # nothing suitable to merge here
1239 $ hg debugsetparents 0 1 # nothing suitable to merge here
1240 $ hg log --template='{rev}:{node}\n'
1240 $ hg log --template='{rev}:{node}\n'
1241 1:a765632148dc55d38c35c4f247c618701886cb2f
1241 1:a765632148dc55d38c35c4f247c618701886cb2f
1242 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1242 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1243 $ hg debugsetparents 1
1243 $ hg debugsetparents 1
1244 $ hg up -q null
1244 $ hg up -q null
1245
1245
1246 bookmarks prevent a changeset being hidden
1246 bookmarks prevent a changeset being hidden
1247
1247
1248 $ hg bookmark --hidden -r 1 X
1248 $ hg bookmark --hidden -r 1 X
1249 $ hg log --template '{rev}:{node}\n'
1249 $ hg log --template '{rev}:{node}\n'
1250 1:a765632148dc55d38c35c4f247c618701886cb2f
1250 1:a765632148dc55d38c35c4f247c618701886cb2f
1251 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1251 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1252 $ hg bookmark -d X
1252 $ hg bookmark -d X
1253
1253
1254 divergent bookmarks are not hidden
1254 divergent bookmarks are not hidden
1255
1255
1256 $ hg bookmark --hidden -r 1 X@foo
1256 $ hg bookmark --hidden -r 1 X@foo
1257 $ hg log --template '{rev}:{node}\n'
1257 $ hg log --template '{rev}:{node}\n'
1258 1:a765632148dc55d38c35c4f247c618701886cb2f
1258 1:a765632148dc55d38c35c4f247c618701886cb2f
1259 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1259 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1260
1260
1261 clear extensions configuration
1261 clear extensions configuration
1262 $ echo '[extensions]' >> $HGRCPATH
1262 $ echo '[extensions]' >> $HGRCPATH
1263 $ echo "obs=!" >> $HGRCPATH
1263 $ echo "obs=!" >> $HGRCPATH
1264 $ cd ..
1264 $ cd ..
1265
1265
1266 test -u/-k for problematic encoding
1266 test -u/-k for problematic encoding
1267 # unicode: cp932:
1267 # unicode: cp932:
1268 # u30A2 0x83 0x41(= 'A')
1268 # u30A2 0x83 0x41(= 'A')
1269 # u30C2 0x83 0x61(= 'a')
1269 # u30C2 0x83 0x61(= 'a')
1270
1270
1271 $ hg init problematicencoding
1271 $ hg init problematicencoding
1272 $ cd problematicencoding
1272 $ cd problematicencoding
1273
1273
1274 $ python > setup.sh <<EOF
1274 $ python > setup.sh <<EOF
1275 > print u'''
1275 > print u'''
1276 > echo a > text
1276 > echo a > text
1277 > hg add text
1277 > hg add text
1278 > hg --encoding utf-8 commit -u '\u30A2' -m none
1278 > hg --encoding utf-8 commit -u '\u30A2' -m none
1279 > echo b > text
1279 > echo b > text
1280 > hg --encoding utf-8 commit -u '\u30C2' -m none
1280 > hg --encoding utf-8 commit -u '\u30C2' -m none
1281 > echo c > text
1281 > echo c > text
1282 > hg --encoding utf-8 commit -u none -m '\u30A2'
1282 > hg --encoding utf-8 commit -u none -m '\u30A2'
1283 > echo d > text
1283 > echo d > text
1284 > hg --encoding utf-8 commit -u none -m '\u30C2'
1284 > hg --encoding utf-8 commit -u none -m '\u30C2'
1285 > '''.encode('utf-8')
1285 > '''.encode('utf-8')
1286 > EOF
1286 > EOF
1287 $ sh < setup.sh
1287 $ sh < setup.sh
1288
1288
1289 test in problematic encoding
1289 test in problematic encoding
1290 $ python > test.sh <<EOF
1290 $ python > test.sh <<EOF
1291 > print u'''
1291 > print u'''
1292 > hg --encoding cp932 log --template '{rev}\\n' -u '\u30A2'
1292 > hg --encoding cp932 log --template '{rev}\\n' -u '\u30A2'
1293 > echo ====
1293 > echo ====
1294 > hg --encoding cp932 log --template '{rev}\\n' -u '\u30C2'
1294 > hg --encoding cp932 log --template '{rev}\\n' -u '\u30C2'
1295 > echo ====
1295 > echo ====
1296 > hg --encoding cp932 log --template '{rev}\\n' -k '\u30A2'
1296 > hg --encoding cp932 log --template '{rev}\\n' -k '\u30A2'
1297 > echo ====
1297 > echo ====
1298 > hg --encoding cp932 log --template '{rev}\\n' -k '\u30C2'
1298 > hg --encoding cp932 log --template '{rev}\\n' -k '\u30C2'
1299 > '''.encode('cp932')
1299 > '''.encode('cp932')
1300 > EOF
1300 > EOF
1301 $ sh < test.sh
1301 $ sh < test.sh
1302 0
1302 0
1303 ====
1303 ====
1304 1
1304 1
1305 ====
1305 ====
1306 2
1306 2
1307 0
1307 0
1308 ====
1308 ====
1309 3
1309 3
1310 1
1310 1
1311
1311
1312 $ cd ..
1312 $ cd ..
1313
1313
1314 test hg log on non-existent files and on directories
1314 test hg log on non-existent files and on directories
1315 $ hg init issue1340
1315 $ hg init issue1340
1316 $ cd issue1340
1316 $ cd issue1340
1317 $ mkdir d1; mkdir D2; mkdir D3.i; mkdir d4.hg; mkdir d5.d; mkdir .d6
1317 $ mkdir d1; mkdir D2; mkdir D3.i; mkdir d4.hg; mkdir d5.d; mkdir .d6
1318 $ echo 1 > d1/f1
1318 $ echo 1 > d1/f1
1319 $ echo 1 > D2/f1
1319 $ echo 1 > D2/f1
1320 $ echo 1 > D3.i/f1
1320 $ echo 1 > D3.i/f1
1321 $ echo 1 > d4.hg/f1
1321 $ echo 1 > d4.hg/f1
1322 $ echo 1 > d5.d/f1
1322 $ echo 1 > d5.d/f1
1323 $ echo 1 > .d6/f1
1323 $ echo 1 > .d6/f1
1324 $ hg -q add .
1324 $ hg -q add .
1325 $ hg commit -m "a bunch of weird directories"
1325 $ hg commit -m "a bunch of weird directories"
1326 $ hg log -l1 d1/f1 | grep changeset
1326 $ hg log -l1 d1/f1 | grep changeset
1327 changeset: 0:65624cd9070a
1327 changeset: 0:65624cd9070a
1328 $ hg log -l1 f1
1328 $ hg log -l1 f1
1329 $ hg log -l1 . | grep changeset
1329 $ hg log -l1 . | grep changeset
1330 changeset: 0:65624cd9070a
1330 changeset: 0:65624cd9070a
1331 $ hg log -l1 ./ | grep changeset
1331 $ hg log -l1 ./ | grep changeset
1332 changeset: 0:65624cd9070a
1332 changeset: 0:65624cd9070a
1333 $ hg log -l1 d1 | grep changeset
1333 $ hg log -l1 d1 | grep changeset
1334 changeset: 0:65624cd9070a
1334 changeset: 0:65624cd9070a
1335 $ hg log -l1 D2 | grep changeset
1335 $ hg log -l1 D2 | grep changeset
1336 changeset: 0:65624cd9070a
1336 changeset: 0:65624cd9070a
1337 $ hg log -l1 D2/f1 | grep changeset
1337 $ hg log -l1 D2/f1 | grep changeset
1338 changeset: 0:65624cd9070a
1338 changeset: 0:65624cd9070a
1339 $ hg log -l1 D3.i | grep changeset
1339 $ hg log -l1 D3.i | grep changeset
1340 changeset: 0:65624cd9070a
1340 changeset: 0:65624cd9070a
1341 $ hg log -l1 D3.i/f1 | grep changeset
1341 $ hg log -l1 D3.i/f1 | grep changeset
1342 changeset: 0:65624cd9070a
1342 changeset: 0:65624cd9070a
1343 $ hg log -l1 d4.hg | grep changeset
1343 $ hg log -l1 d4.hg | grep changeset
1344 changeset: 0:65624cd9070a
1344 changeset: 0:65624cd9070a
1345 $ hg log -l1 d4.hg/f1 | grep changeset
1345 $ hg log -l1 d4.hg/f1 | grep changeset
1346 changeset: 0:65624cd9070a
1346 changeset: 0:65624cd9070a
1347 $ hg log -l1 d5.d | grep changeset
1347 $ hg log -l1 d5.d | grep changeset
1348 changeset: 0:65624cd9070a
1348 changeset: 0:65624cd9070a
1349 $ hg log -l1 d5.d/f1 | grep changeset
1349 $ hg log -l1 d5.d/f1 | grep changeset
1350 changeset: 0:65624cd9070a
1350 changeset: 0:65624cd9070a
1351 $ hg log -l1 .d6 | grep changeset
1351 $ hg log -l1 .d6 | grep changeset
1352 changeset: 0:65624cd9070a
1352 changeset: 0:65624cd9070a
1353 $ hg log -l1 .d6/f1 | grep changeset
1353 $ hg log -l1 .d6/f1 | grep changeset
1354 changeset: 0:65624cd9070a
1354 changeset: 0:65624cd9070a
1355
1355
1356 issue3772: hg log -r :null showing revision 0 as well
1356 issue3772: hg log -r :null showing revision 0 as well
1357
1357
1358 $ hg log -r :null
1358 $ hg log -r :null
1359 changeset: 0:65624cd9070a
1360 tag: tip
1361 user: test
1362 date: Thu Jan 01 00:00:00 1970 +0000
1363 summary: a bunch of weird directories
1364
1359 changeset: -1:000000000000
1365 changeset: -1:000000000000
1360 user:
1366 user:
1361 date: Thu Jan 01 00:00:00 1970 +0000
1367 date: Thu Jan 01 00:00:00 1970 +0000
1362
1368
1363 $ hg log -r null:null
1369 $ hg log -r null:null
1364 changeset: -1:000000000000
1370 changeset: -1:000000000000
1365 user:
1371 user:
1366 date: Thu Jan 01 00:00:00 1970 +0000
1372 date: Thu Jan 01 00:00:00 1970 +0000
1367
1373
1368
1374
1369 $ cd ..
1375 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now