##// END OF EJS Templates
log: fix --follow FILE ancestry calculation...
Patrick Mezard -
r16165:60101427 stable
parent child Browse files
Show More
@@ -1,1319 +1,1326 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 subrepo
13 import subrepo
14
14
15 def parsealiases(cmd):
15 def parsealiases(cmd):
16 return cmd.lstrip("^").split("|")
16 return cmd.lstrip("^").split("|")
17
17
18 def findpossible(cmd, table, strict=False):
18 def findpossible(cmd, table, strict=False):
19 """
19 """
20 Return cmd -> (aliases, command table entry)
20 Return cmd -> (aliases, command table entry)
21 for each matching command.
21 for each matching command.
22 Return debug commands (or their aliases) only if no normal command matches.
22 Return debug commands (or their aliases) only if no normal command matches.
23 """
23 """
24 choice = {}
24 choice = {}
25 debugchoice = {}
25 debugchoice = {}
26
26
27 if cmd in table:
27 if cmd in table:
28 # short-circuit exact matches, "log" alias beats "^log|history"
28 # short-circuit exact matches, "log" alias beats "^log|history"
29 keys = [cmd]
29 keys = [cmd]
30 else:
30 else:
31 keys = table.keys()
31 keys = table.keys()
32
32
33 for e in keys:
33 for e in keys:
34 aliases = parsealiases(e)
34 aliases = parsealiases(e)
35 found = None
35 found = None
36 if cmd in aliases:
36 if cmd in aliases:
37 found = cmd
37 found = cmd
38 elif not strict:
38 elif not strict:
39 for a in aliases:
39 for a in aliases:
40 if a.startswith(cmd):
40 if a.startswith(cmd):
41 found = a
41 found = a
42 break
42 break
43 if found is not None:
43 if found is not None:
44 if aliases[0].startswith("debug") or found.startswith("debug"):
44 if aliases[0].startswith("debug") or found.startswith("debug"):
45 debugchoice[found] = (aliases, table[e])
45 debugchoice[found] = (aliases, table[e])
46 else:
46 else:
47 choice[found] = (aliases, table[e])
47 choice[found] = (aliases, table[e])
48
48
49 if not choice and debugchoice:
49 if not choice and debugchoice:
50 choice = debugchoice
50 choice = debugchoice
51
51
52 return choice
52 return choice
53
53
54 def findcmd(cmd, table, strict=True):
54 def findcmd(cmd, table, strict=True):
55 """Return (aliases, command table entry) for command string."""
55 """Return (aliases, command table entry) for command string."""
56 choice = findpossible(cmd, table, strict)
56 choice = findpossible(cmd, table, strict)
57
57
58 if cmd in choice:
58 if cmd in choice:
59 return choice[cmd]
59 return choice[cmd]
60
60
61 if len(choice) > 1:
61 if len(choice) > 1:
62 clist = choice.keys()
62 clist = choice.keys()
63 clist.sort()
63 clist.sort()
64 raise error.AmbiguousCommand(cmd, clist)
64 raise error.AmbiguousCommand(cmd, clist)
65
65
66 if choice:
66 if choice:
67 return choice.values()[0]
67 return choice.values()[0]
68
68
69 raise error.UnknownCommand(cmd)
69 raise error.UnknownCommand(cmd)
70
70
71 def findrepo(p):
71 def findrepo(p):
72 while not os.path.isdir(os.path.join(p, ".hg")):
72 while not os.path.isdir(os.path.join(p, ".hg")):
73 oldp, p = p, os.path.dirname(p)
73 oldp, p = p, os.path.dirname(p)
74 if p == oldp:
74 if p == oldp:
75 return None
75 return None
76
76
77 return p
77 return p
78
78
79 def bailifchanged(repo):
79 def bailifchanged(repo):
80 if repo.dirstate.p2() != nullid:
80 if repo.dirstate.p2() != nullid:
81 raise util.Abort(_('outstanding uncommitted merge'))
81 raise util.Abort(_('outstanding uncommitted merge'))
82 modified, added, removed, deleted = repo.status()[:4]
82 modified, added, removed, deleted = repo.status()[:4]
83 if modified or added or removed or deleted:
83 if modified or added or removed or deleted:
84 raise util.Abort(_("outstanding uncommitted changes"))
84 raise util.Abort(_("outstanding uncommitted changes"))
85 ctx = repo[None]
85 ctx = repo[None]
86 for s in ctx.substate:
86 for s in ctx.substate:
87 if ctx.sub(s).dirty():
87 if ctx.sub(s).dirty():
88 raise util.Abort(_("uncommitted changes in subrepo %s") % s)
88 raise util.Abort(_("uncommitted changes in subrepo %s") % s)
89
89
90 def logmessage(ui, opts):
90 def logmessage(ui, opts):
91 """ get the log message according to -m and -l option """
91 """ get the log message according to -m and -l option """
92 message = opts.get('message')
92 message = opts.get('message')
93 logfile = opts.get('logfile')
93 logfile = opts.get('logfile')
94
94
95 if message and logfile:
95 if message and logfile:
96 raise util.Abort(_('options --message and --logfile are mutually '
96 raise util.Abort(_('options --message and --logfile are mutually '
97 'exclusive'))
97 'exclusive'))
98 if not message and logfile:
98 if not message and logfile:
99 try:
99 try:
100 if logfile == '-':
100 if logfile == '-':
101 message = ui.fin.read()
101 message = ui.fin.read()
102 else:
102 else:
103 message = '\n'.join(util.readfile(logfile).splitlines())
103 message = '\n'.join(util.readfile(logfile).splitlines())
104 except IOError, inst:
104 except IOError, inst:
105 raise util.Abort(_("can't read commit message '%s': %s") %
105 raise util.Abort(_("can't read commit message '%s': %s") %
106 (logfile, inst.strerror))
106 (logfile, inst.strerror))
107 return message
107 return message
108
108
109 def loglimit(opts):
109 def loglimit(opts):
110 """get the log limit according to option -l/--limit"""
110 """get the log limit according to option -l/--limit"""
111 limit = opts.get('limit')
111 limit = opts.get('limit')
112 if limit:
112 if limit:
113 try:
113 try:
114 limit = int(limit)
114 limit = int(limit)
115 except ValueError:
115 except ValueError:
116 raise util.Abort(_('limit must be a positive integer'))
116 raise util.Abort(_('limit must be a positive integer'))
117 if limit <= 0:
117 if limit <= 0:
118 raise util.Abort(_('limit must be positive'))
118 raise util.Abort(_('limit must be positive'))
119 else:
119 else:
120 limit = None
120 limit = None
121 return limit
121 return limit
122
122
123 def makefilename(repo, pat, node, desc=None,
123 def makefilename(repo, pat, node, desc=None,
124 total=None, seqno=None, revwidth=None, pathname=None):
124 total=None, seqno=None, revwidth=None, pathname=None):
125 node_expander = {
125 node_expander = {
126 'H': lambda: hex(node),
126 'H': lambda: hex(node),
127 'R': lambda: str(repo.changelog.rev(node)),
127 'R': lambda: str(repo.changelog.rev(node)),
128 'h': lambda: short(node),
128 'h': lambda: short(node),
129 'm': lambda: re.sub('[^\w]', '_', str(desc))
129 'm': lambda: re.sub('[^\w]', '_', str(desc))
130 }
130 }
131 expander = {
131 expander = {
132 '%': lambda: '%',
132 '%': lambda: '%',
133 'b': lambda: os.path.basename(repo.root),
133 'b': lambda: os.path.basename(repo.root),
134 }
134 }
135
135
136 try:
136 try:
137 if node:
137 if node:
138 expander.update(node_expander)
138 expander.update(node_expander)
139 if node:
139 if node:
140 expander['r'] = (lambda:
140 expander['r'] = (lambda:
141 str(repo.changelog.rev(node)).zfill(revwidth or 0))
141 str(repo.changelog.rev(node)).zfill(revwidth or 0))
142 if total is not None:
142 if total is not None:
143 expander['N'] = lambda: str(total)
143 expander['N'] = lambda: str(total)
144 if seqno is not None:
144 if seqno is not None:
145 expander['n'] = lambda: str(seqno)
145 expander['n'] = lambda: str(seqno)
146 if total is not None and seqno is not None:
146 if total is not None and seqno is not None:
147 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
147 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
148 if pathname is not None:
148 if pathname is not None:
149 expander['s'] = lambda: os.path.basename(pathname)
149 expander['s'] = lambda: os.path.basename(pathname)
150 expander['d'] = lambda: os.path.dirname(pathname) or '.'
150 expander['d'] = lambda: os.path.dirname(pathname) or '.'
151 expander['p'] = lambda: pathname
151 expander['p'] = lambda: pathname
152
152
153 newname = []
153 newname = []
154 patlen = len(pat)
154 patlen = len(pat)
155 i = 0
155 i = 0
156 while i < patlen:
156 while i < patlen:
157 c = pat[i]
157 c = pat[i]
158 if c == '%':
158 if c == '%':
159 i += 1
159 i += 1
160 c = pat[i]
160 c = pat[i]
161 c = expander[c]()
161 c = expander[c]()
162 newname.append(c)
162 newname.append(c)
163 i += 1
163 i += 1
164 return ''.join(newname)
164 return ''.join(newname)
165 except KeyError, inst:
165 except KeyError, inst:
166 raise util.Abort(_("invalid format spec '%%%s' in output filename") %
166 raise util.Abort(_("invalid format spec '%%%s' in output filename") %
167 inst.args[0])
167 inst.args[0])
168
168
169 def makefileobj(repo, pat, node=None, desc=None, total=None,
169 def makefileobj(repo, pat, node=None, desc=None, total=None,
170 seqno=None, revwidth=None, mode='wb', pathname=None):
170 seqno=None, revwidth=None, mode='wb', pathname=None):
171
171
172 writable = mode not in ('r', 'rb')
172 writable = mode not in ('r', 'rb')
173
173
174 if not pat or pat == '-':
174 if not pat or pat == '-':
175 fp = writable and repo.ui.fout or repo.ui.fin
175 fp = writable and repo.ui.fout or repo.ui.fin
176 if util.safehasattr(fp, 'fileno'):
176 if util.safehasattr(fp, 'fileno'):
177 return os.fdopen(os.dup(fp.fileno()), mode)
177 return os.fdopen(os.dup(fp.fileno()), mode)
178 else:
178 else:
179 # if this fp can't be duped properly, return
179 # if this fp can't be duped properly, return
180 # a dummy object that can be closed
180 # a dummy object that can be closed
181 class wrappedfileobj(object):
181 class wrappedfileobj(object):
182 noop = lambda x: None
182 noop = lambda x: None
183 def __init__(self, f):
183 def __init__(self, f):
184 self.f = f
184 self.f = f
185 def __getattr__(self, attr):
185 def __getattr__(self, attr):
186 if attr == 'close':
186 if attr == 'close':
187 return self.noop
187 return self.noop
188 else:
188 else:
189 return getattr(self.f, attr)
189 return getattr(self.f, attr)
190
190
191 return wrappedfileobj(fp)
191 return wrappedfileobj(fp)
192 if util.safehasattr(pat, 'write') and writable:
192 if util.safehasattr(pat, 'write') and writable:
193 return pat
193 return pat
194 if util.safehasattr(pat, 'read') and 'r' in mode:
194 if util.safehasattr(pat, 'read') and 'r' in mode:
195 return pat
195 return pat
196 return open(makefilename(repo, pat, node, desc, total, seqno, revwidth,
196 return open(makefilename(repo, pat, node, desc, total, seqno, revwidth,
197 pathname),
197 pathname),
198 mode)
198 mode)
199
199
200 def openrevlog(repo, cmd, file_, opts):
200 def openrevlog(repo, cmd, file_, opts):
201 """opens the changelog, manifest, a filelog or a given revlog"""
201 """opens the changelog, manifest, a filelog or a given revlog"""
202 cl = opts['changelog']
202 cl = opts['changelog']
203 mf = opts['manifest']
203 mf = opts['manifest']
204 msg = None
204 msg = None
205 if cl and mf:
205 if cl and mf:
206 msg = _('cannot specify --changelog and --manifest at the same time')
206 msg = _('cannot specify --changelog and --manifest at the same time')
207 elif cl or mf:
207 elif cl or mf:
208 if file_:
208 if file_:
209 msg = _('cannot specify filename with --changelog or --manifest')
209 msg = _('cannot specify filename with --changelog or --manifest')
210 elif not repo:
210 elif not repo:
211 msg = _('cannot specify --changelog or --manifest '
211 msg = _('cannot specify --changelog or --manifest '
212 'without a repository')
212 'without a repository')
213 if msg:
213 if msg:
214 raise util.Abort(msg)
214 raise util.Abort(msg)
215
215
216 r = None
216 r = None
217 if repo:
217 if repo:
218 if cl:
218 if cl:
219 r = repo.changelog
219 r = repo.changelog
220 elif mf:
220 elif mf:
221 r = repo.manifest
221 r = repo.manifest
222 elif file_:
222 elif file_:
223 filelog = repo.file(file_)
223 filelog = repo.file(file_)
224 if len(filelog):
224 if len(filelog):
225 r = filelog
225 r = filelog
226 if not r:
226 if not r:
227 if not file_:
227 if not file_:
228 raise error.CommandError(cmd, _('invalid arguments'))
228 raise error.CommandError(cmd, _('invalid arguments'))
229 if not os.path.isfile(file_):
229 if not os.path.isfile(file_):
230 raise util.Abort(_("revlog '%s' not found") % file_)
230 raise util.Abort(_("revlog '%s' not found") % file_)
231 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
231 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
232 file_[:-2] + ".i")
232 file_[:-2] + ".i")
233 return r
233 return r
234
234
235 def copy(ui, repo, pats, opts, rename=False):
235 def copy(ui, repo, pats, opts, rename=False):
236 # called with the repo lock held
236 # called with the repo lock held
237 #
237 #
238 # hgsep => pathname that uses "/" to separate directories
238 # hgsep => pathname that uses "/" to separate directories
239 # ossep => pathname that uses os.sep to separate directories
239 # ossep => pathname that uses os.sep to separate directories
240 cwd = repo.getcwd()
240 cwd = repo.getcwd()
241 targets = {}
241 targets = {}
242 after = opts.get("after")
242 after = opts.get("after")
243 dryrun = opts.get("dry_run")
243 dryrun = opts.get("dry_run")
244 wctx = repo[None]
244 wctx = repo[None]
245
245
246 def walkpat(pat):
246 def walkpat(pat):
247 srcs = []
247 srcs = []
248 badstates = after and '?' or '?r'
248 badstates = after and '?' or '?r'
249 m = scmutil.match(repo[None], [pat], opts, globbed=True)
249 m = scmutil.match(repo[None], [pat], opts, globbed=True)
250 for abs in repo.walk(m):
250 for abs in repo.walk(m):
251 state = repo.dirstate[abs]
251 state = repo.dirstate[abs]
252 rel = m.rel(abs)
252 rel = m.rel(abs)
253 exact = m.exact(abs)
253 exact = m.exact(abs)
254 if state in badstates:
254 if state in badstates:
255 if exact and state == '?':
255 if exact and state == '?':
256 ui.warn(_('%s: not copying - file is not managed\n') % rel)
256 ui.warn(_('%s: not copying - file is not managed\n') % rel)
257 if exact and state == 'r':
257 if exact and state == 'r':
258 ui.warn(_('%s: not copying - file has been marked for'
258 ui.warn(_('%s: not copying - file has been marked for'
259 ' remove\n') % rel)
259 ' remove\n') % rel)
260 continue
260 continue
261 # abs: hgsep
261 # abs: hgsep
262 # rel: ossep
262 # rel: ossep
263 srcs.append((abs, rel, exact))
263 srcs.append((abs, rel, exact))
264 return srcs
264 return srcs
265
265
266 # abssrc: hgsep
266 # abssrc: hgsep
267 # relsrc: ossep
267 # relsrc: ossep
268 # otarget: ossep
268 # otarget: ossep
269 def copyfile(abssrc, relsrc, otarget, exact):
269 def copyfile(abssrc, relsrc, otarget, exact):
270 abstarget = scmutil.canonpath(repo.root, cwd, otarget)
270 abstarget = scmutil.canonpath(repo.root, cwd, otarget)
271 reltarget = repo.pathto(abstarget, cwd)
271 reltarget = repo.pathto(abstarget, cwd)
272 target = repo.wjoin(abstarget)
272 target = repo.wjoin(abstarget)
273 src = repo.wjoin(abssrc)
273 src = repo.wjoin(abssrc)
274 state = repo.dirstate[abstarget]
274 state = repo.dirstate[abstarget]
275
275
276 scmutil.checkportable(ui, abstarget)
276 scmutil.checkportable(ui, abstarget)
277
277
278 # check for collisions
278 # check for collisions
279 prevsrc = targets.get(abstarget)
279 prevsrc = targets.get(abstarget)
280 if prevsrc is not None:
280 if prevsrc is not None:
281 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
281 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
282 (reltarget, repo.pathto(abssrc, cwd),
282 (reltarget, repo.pathto(abssrc, cwd),
283 repo.pathto(prevsrc, cwd)))
283 repo.pathto(prevsrc, cwd)))
284 return
284 return
285
285
286 # check for overwrites
286 # check for overwrites
287 exists = os.path.lexists(target)
287 exists = os.path.lexists(target)
288 if not after and exists or after and state in 'mn':
288 if not after and exists or after and state in 'mn':
289 if not opts['force']:
289 if not opts['force']:
290 ui.warn(_('%s: not overwriting - file exists\n') %
290 ui.warn(_('%s: not overwriting - file exists\n') %
291 reltarget)
291 reltarget)
292 return
292 return
293
293
294 if after:
294 if after:
295 if not exists:
295 if not exists:
296 if rename:
296 if rename:
297 ui.warn(_('%s: not recording move - %s does not exist\n') %
297 ui.warn(_('%s: not recording move - %s does not exist\n') %
298 (relsrc, reltarget))
298 (relsrc, reltarget))
299 else:
299 else:
300 ui.warn(_('%s: not recording copy - %s does not exist\n') %
300 ui.warn(_('%s: not recording copy - %s does not exist\n') %
301 (relsrc, reltarget))
301 (relsrc, reltarget))
302 return
302 return
303 elif not dryrun:
303 elif not dryrun:
304 try:
304 try:
305 if exists:
305 if exists:
306 os.unlink(target)
306 os.unlink(target)
307 targetdir = os.path.dirname(target) or '.'
307 targetdir = os.path.dirname(target) or '.'
308 if not os.path.isdir(targetdir):
308 if not os.path.isdir(targetdir):
309 os.makedirs(targetdir)
309 os.makedirs(targetdir)
310 util.copyfile(src, target)
310 util.copyfile(src, target)
311 srcexists = True
311 srcexists = True
312 except IOError, inst:
312 except IOError, inst:
313 if inst.errno == errno.ENOENT:
313 if inst.errno == errno.ENOENT:
314 ui.warn(_('%s: deleted in working copy\n') % relsrc)
314 ui.warn(_('%s: deleted in working copy\n') % relsrc)
315 srcexists = False
315 srcexists = False
316 else:
316 else:
317 ui.warn(_('%s: cannot copy - %s\n') %
317 ui.warn(_('%s: cannot copy - %s\n') %
318 (relsrc, inst.strerror))
318 (relsrc, inst.strerror))
319 return True # report a failure
319 return True # report a failure
320
320
321 if ui.verbose or not exact:
321 if ui.verbose or not exact:
322 if rename:
322 if rename:
323 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
323 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
324 else:
324 else:
325 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
325 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
326
326
327 targets[abstarget] = abssrc
327 targets[abstarget] = abssrc
328
328
329 # fix up dirstate
329 # fix up dirstate
330 scmutil.dirstatecopy(ui, repo, wctx, abssrc, abstarget,
330 scmutil.dirstatecopy(ui, repo, wctx, abssrc, abstarget,
331 dryrun=dryrun, cwd=cwd)
331 dryrun=dryrun, cwd=cwd)
332 if rename and not dryrun:
332 if rename and not dryrun:
333 if not after and srcexists:
333 if not after and srcexists:
334 util.unlinkpath(repo.wjoin(abssrc))
334 util.unlinkpath(repo.wjoin(abssrc))
335 wctx.forget([abssrc])
335 wctx.forget([abssrc])
336
336
337 # pat: ossep
337 # pat: ossep
338 # dest ossep
338 # dest ossep
339 # srcs: list of (hgsep, hgsep, ossep, bool)
339 # srcs: list of (hgsep, hgsep, ossep, bool)
340 # return: function that takes hgsep and returns ossep
340 # return: function that takes hgsep and returns ossep
341 def targetpathfn(pat, dest, srcs):
341 def targetpathfn(pat, dest, srcs):
342 if os.path.isdir(pat):
342 if os.path.isdir(pat):
343 abspfx = scmutil.canonpath(repo.root, cwd, pat)
343 abspfx = scmutil.canonpath(repo.root, cwd, pat)
344 abspfx = util.localpath(abspfx)
344 abspfx = util.localpath(abspfx)
345 if destdirexists:
345 if destdirexists:
346 striplen = len(os.path.split(abspfx)[0])
346 striplen = len(os.path.split(abspfx)[0])
347 else:
347 else:
348 striplen = len(abspfx)
348 striplen = len(abspfx)
349 if striplen:
349 if striplen:
350 striplen += len(os.sep)
350 striplen += len(os.sep)
351 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
351 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
352 elif destdirexists:
352 elif destdirexists:
353 res = lambda p: os.path.join(dest,
353 res = lambda p: os.path.join(dest,
354 os.path.basename(util.localpath(p)))
354 os.path.basename(util.localpath(p)))
355 else:
355 else:
356 res = lambda p: dest
356 res = lambda p: dest
357 return res
357 return res
358
358
359 # pat: ossep
359 # pat: ossep
360 # dest ossep
360 # dest ossep
361 # srcs: list of (hgsep, hgsep, ossep, bool)
361 # srcs: list of (hgsep, hgsep, ossep, bool)
362 # return: function that takes hgsep and returns ossep
362 # return: function that takes hgsep and returns ossep
363 def targetpathafterfn(pat, dest, srcs):
363 def targetpathafterfn(pat, dest, srcs):
364 if matchmod.patkind(pat):
364 if matchmod.patkind(pat):
365 # a mercurial pattern
365 # a mercurial pattern
366 res = lambda p: os.path.join(dest,
366 res = lambda p: os.path.join(dest,
367 os.path.basename(util.localpath(p)))
367 os.path.basename(util.localpath(p)))
368 else:
368 else:
369 abspfx = scmutil.canonpath(repo.root, cwd, pat)
369 abspfx = scmutil.canonpath(repo.root, cwd, pat)
370 if len(abspfx) < len(srcs[0][0]):
370 if len(abspfx) < len(srcs[0][0]):
371 # A directory. Either the target path contains the last
371 # A directory. Either the target path contains the last
372 # component of the source path or it does not.
372 # component of the source path or it does not.
373 def evalpath(striplen):
373 def evalpath(striplen):
374 score = 0
374 score = 0
375 for s in srcs:
375 for s in srcs:
376 t = os.path.join(dest, util.localpath(s[0])[striplen:])
376 t = os.path.join(dest, util.localpath(s[0])[striplen:])
377 if os.path.lexists(t):
377 if os.path.lexists(t):
378 score += 1
378 score += 1
379 return score
379 return score
380
380
381 abspfx = util.localpath(abspfx)
381 abspfx = util.localpath(abspfx)
382 striplen = len(abspfx)
382 striplen = len(abspfx)
383 if striplen:
383 if striplen:
384 striplen += len(os.sep)
384 striplen += len(os.sep)
385 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
385 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
386 score = evalpath(striplen)
386 score = evalpath(striplen)
387 striplen1 = len(os.path.split(abspfx)[0])
387 striplen1 = len(os.path.split(abspfx)[0])
388 if striplen1:
388 if striplen1:
389 striplen1 += len(os.sep)
389 striplen1 += len(os.sep)
390 if evalpath(striplen1) > score:
390 if evalpath(striplen1) > score:
391 striplen = striplen1
391 striplen = striplen1
392 res = lambda p: os.path.join(dest,
392 res = lambda p: os.path.join(dest,
393 util.localpath(p)[striplen:])
393 util.localpath(p)[striplen:])
394 else:
394 else:
395 # a file
395 # a file
396 if destdirexists:
396 if destdirexists:
397 res = lambda p: os.path.join(dest,
397 res = lambda p: os.path.join(dest,
398 os.path.basename(util.localpath(p)))
398 os.path.basename(util.localpath(p)))
399 else:
399 else:
400 res = lambda p: dest
400 res = lambda p: dest
401 return res
401 return res
402
402
403
403
404 pats = scmutil.expandpats(pats)
404 pats = scmutil.expandpats(pats)
405 if not pats:
405 if not pats:
406 raise util.Abort(_('no source or destination specified'))
406 raise util.Abort(_('no source or destination specified'))
407 if len(pats) == 1:
407 if len(pats) == 1:
408 raise util.Abort(_('no destination specified'))
408 raise util.Abort(_('no destination specified'))
409 dest = pats.pop()
409 dest = pats.pop()
410 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
410 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
411 if not destdirexists:
411 if not destdirexists:
412 if len(pats) > 1 or matchmod.patkind(pats[0]):
412 if len(pats) > 1 or matchmod.patkind(pats[0]):
413 raise util.Abort(_('with multiple sources, destination must be an '
413 raise util.Abort(_('with multiple sources, destination must be an '
414 'existing directory'))
414 'existing directory'))
415 if util.endswithsep(dest):
415 if util.endswithsep(dest):
416 raise util.Abort(_('destination %s is not a directory') % dest)
416 raise util.Abort(_('destination %s is not a directory') % dest)
417
417
418 tfn = targetpathfn
418 tfn = targetpathfn
419 if after:
419 if after:
420 tfn = targetpathafterfn
420 tfn = targetpathafterfn
421 copylist = []
421 copylist = []
422 for pat in pats:
422 for pat in pats:
423 srcs = walkpat(pat)
423 srcs = walkpat(pat)
424 if not srcs:
424 if not srcs:
425 continue
425 continue
426 copylist.append((tfn(pat, dest, srcs), srcs))
426 copylist.append((tfn(pat, dest, srcs), srcs))
427 if not copylist:
427 if not copylist:
428 raise util.Abort(_('no files to copy'))
428 raise util.Abort(_('no files to copy'))
429
429
430 errors = 0
430 errors = 0
431 for targetpath, srcs in copylist:
431 for targetpath, srcs in copylist:
432 for abssrc, relsrc, exact in srcs:
432 for abssrc, relsrc, exact in srcs:
433 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
433 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
434 errors += 1
434 errors += 1
435
435
436 if errors:
436 if errors:
437 ui.warn(_('(consider using --after)\n'))
437 ui.warn(_('(consider using --after)\n'))
438
438
439 return errors != 0
439 return errors != 0
440
440
441 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
441 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
442 runargs=None, appendpid=False):
442 runargs=None, appendpid=False):
443 '''Run a command as a service.'''
443 '''Run a command as a service.'''
444
444
445 if opts['daemon'] and not opts['daemon_pipefds']:
445 if opts['daemon'] and not opts['daemon_pipefds']:
446 # Signal child process startup with file removal
446 # Signal child process startup with file removal
447 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
447 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
448 os.close(lockfd)
448 os.close(lockfd)
449 try:
449 try:
450 if not runargs:
450 if not runargs:
451 runargs = util.hgcmd() + sys.argv[1:]
451 runargs = util.hgcmd() + sys.argv[1:]
452 runargs.append('--daemon-pipefds=%s' % lockpath)
452 runargs.append('--daemon-pipefds=%s' % lockpath)
453 # Don't pass --cwd to the child process, because we've already
453 # Don't pass --cwd to the child process, because we've already
454 # changed directory.
454 # changed directory.
455 for i in xrange(1, len(runargs)):
455 for i in xrange(1, len(runargs)):
456 if runargs[i].startswith('--cwd='):
456 if runargs[i].startswith('--cwd='):
457 del runargs[i]
457 del runargs[i]
458 break
458 break
459 elif runargs[i].startswith('--cwd'):
459 elif runargs[i].startswith('--cwd'):
460 del runargs[i:i + 2]
460 del runargs[i:i + 2]
461 break
461 break
462 def condfn():
462 def condfn():
463 return not os.path.exists(lockpath)
463 return not os.path.exists(lockpath)
464 pid = util.rundetached(runargs, condfn)
464 pid = util.rundetached(runargs, condfn)
465 if pid < 0:
465 if pid < 0:
466 raise util.Abort(_('child process failed to start'))
466 raise util.Abort(_('child process failed to start'))
467 finally:
467 finally:
468 try:
468 try:
469 os.unlink(lockpath)
469 os.unlink(lockpath)
470 except OSError, e:
470 except OSError, e:
471 if e.errno != errno.ENOENT:
471 if e.errno != errno.ENOENT:
472 raise
472 raise
473 if parentfn:
473 if parentfn:
474 return parentfn(pid)
474 return parentfn(pid)
475 else:
475 else:
476 return
476 return
477
477
478 if initfn:
478 if initfn:
479 initfn()
479 initfn()
480
480
481 if opts['pid_file']:
481 if opts['pid_file']:
482 mode = appendpid and 'a' or 'w'
482 mode = appendpid and 'a' or 'w'
483 fp = open(opts['pid_file'], mode)
483 fp = open(opts['pid_file'], mode)
484 fp.write(str(os.getpid()) + '\n')
484 fp.write(str(os.getpid()) + '\n')
485 fp.close()
485 fp.close()
486
486
487 if opts['daemon_pipefds']:
487 if opts['daemon_pipefds']:
488 lockpath = opts['daemon_pipefds']
488 lockpath = opts['daemon_pipefds']
489 try:
489 try:
490 os.setsid()
490 os.setsid()
491 except AttributeError:
491 except AttributeError:
492 pass
492 pass
493 os.unlink(lockpath)
493 os.unlink(lockpath)
494 util.hidewindow()
494 util.hidewindow()
495 sys.stdout.flush()
495 sys.stdout.flush()
496 sys.stderr.flush()
496 sys.stderr.flush()
497
497
498 nullfd = os.open(util.nulldev, os.O_RDWR)
498 nullfd = os.open(util.nulldev, os.O_RDWR)
499 logfilefd = nullfd
499 logfilefd = nullfd
500 if logfile:
500 if logfile:
501 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
501 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
502 os.dup2(nullfd, 0)
502 os.dup2(nullfd, 0)
503 os.dup2(logfilefd, 1)
503 os.dup2(logfilefd, 1)
504 os.dup2(logfilefd, 2)
504 os.dup2(logfilefd, 2)
505 if nullfd not in (0, 1, 2):
505 if nullfd not in (0, 1, 2):
506 os.close(nullfd)
506 os.close(nullfd)
507 if logfile and logfilefd not in (0, 1, 2):
507 if logfile and logfilefd not in (0, 1, 2):
508 os.close(logfilefd)
508 os.close(logfilefd)
509
509
510 if runfn:
510 if runfn:
511 return runfn()
511 return runfn()
512
512
513 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
513 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
514 opts=None):
514 opts=None):
515 '''export changesets as hg patches.'''
515 '''export changesets as hg patches.'''
516
516
517 total = len(revs)
517 total = len(revs)
518 revwidth = max([len(str(rev)) for rev in revs])
518 revwidth = max([len(str(rev)) for rev in revs])
519
519
520 def single(rev, seqno, fp):
520 def single(rev, seqno, fp):
521 ctx = repo[rev]
521 ctx = repo[rev]
522 node = ctx.node()
522 node = ctx.node()
523 parents = [p.node() for p in ctx.parents() if p]
523 parents = [p.node() for p in ctx.parents() if p]
524 branch = ctx.branch()
524 branch = ctx.branch()
525 if switch_parent:
525 if switch_parent:
526 parents.reverse()
526 parents.reverse()
527 prev = (parents and parents[0]) or nullid
527 prev = (parents and parents[0]) or nullid
528
528
529 shouldclose = False
529 shouldclose = False
530 if not fp:
530 if not fp:
531 desc_lines = ctx.description().rstrip().split('\n')
531 desc_lines = ctx.description().rstrip().split('\n')
532 desc = desc_lines[0] #Commit always has a first line.
532 desc = desc_lines[0] #Commit always has a first line.
533 fp = makefileobj(repo, template, node, desc=desc, total=total,
533 fp = makefileobj(repo, template, node, desc=desc, total=total,
534 seqno=seqno, revwidth=revwidth, mode='ab')
534 seqno=seqno, revwidth=revwidth, mode='ab')
535 if fp != template:
535 if fp != template:
536 shouldclose = True
536 shouldclose = True
537 if fp != sys.stdout and util.safehasattr(fp, 'name'):
537 if fp != sys.stdout and util.safehasattr(fp, 'name'):
538 repo.ui.note("%s\n" % fp.name)
538 repo.ui.note("%s\n" % fp.name)
539
539
540 fp.write("# HG changeset patch\n")
540 fp.write("# HG changeset patch\n")
541 fp.write("# User %s\n" % ctx.user())
541 fp.write("# User %s\n" % ctx.user())
542 fp.write("# Date %d %d\n" % ctx.date())
542 fp.write("# Date %d %d\n" % ctx.date())
543 if branch and branch != 'default':
543 if branch and branch != 'default':
544 fp.write("# Branch %s\n" % branch)
544 fp.write("# Branch %s\n" % branch)
545 fp.write("# Node ID %s\n" % hex(node))
545 fp.write("# Node ID %s\n" % hex(node))
546 fp.write("# Parent %s\n" % hex(prev))
546 fp.write("# Parent %s\n" % hex(prev))
547 if len(parents) > 1:
547 if len(parents) > 1:
548 fp.write("# Parent %s\n" % hex(parents[1]))
548 fp.write("# Parent %s\n" % hex(parents[1]))
549 fp.write(ctx.description().rstrip())
549 fp.write(ctx.description().rstrip())
550 fp.write("\n\n")
550 fp.write("\n\n")
551
551
552 for chunk in patch.diff(repo, prev, node, opts=opts):
552 for chunk in patch.diff(repo, prev, node, opts=opts):
553 fp.write(chunk)
553 fp.write(chunk)
554
554
555 if shouldclose:
555 if shouldclose:
556 fp.close()
556 fp.close()
557
557
558 for seqno, rev in enumerate(revs):
558 for seqno, rev in enumerate(revs):
559 single(rev, seqno + 1, fp)
559 single(rev, seqno + 1, fp)
560
560
561 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
561 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
562 changes=None, stat=False, fp=None, prefix='',
562 changes=None, stat=False, fp=None, prefix='',
563 listsubrepos=False):
563 listsubrepos=False):
564 '''show diff or diffstat.'''
564 '''show diff or diffstat.'''
565 if fp is None:
565 if fp is None:
566 write = ui.write
566 write = ui.write
567 else:
567 else:
568 def write(s, **kw):
568 def write(s, **kw):
569 fp.write(s)
569 fp.write(s)
570
570
571 if stat:
571 if stat:
572 diffopts = diffopts.copy(context=0)
572 diffopts = diffopts.copy(context=0)
573 width = 80
573 width = 80
574 if not ui.plain():
574 if not ui.plain():
575 width = ui.termwidth()
575 width = ui.termwidth()
576 chunks = patch.diff(repo, node1, node2, match, changes, diffopts,
576 chunks = patch.diff(repo, node1, node2, match, changes, diffopts,
577 prefix=prefix)
577 prefix=prefix)
578 for chunk, label in patch.diffstatui(util.iterlines(chunks),
578 for chunk, label in patch.diffstatui(util.iterlines(chunks),
579 width=width,
579 width=width,
580 git=diffopts.git):
580 git=diffopts.git):
581 write(chunk, label=label)
581 write(chunk, label=label)
582 else:
582 else:
583 for chunk, label in patch.diffui(repo, node1, node2, match,
583 for chunk, label in patch.diffui(repo, node1, node2, match,
584 changes, diffopts, prefix=prefix):
584 changes, diffopts, prefix=prefix):
585 write(chunk, label=label)
585 write(chunk, label=label)
586
586
587 if listsubrepos:
587 if listsubrepos:
588 ctx1 = repo[node1]
588 ctx1 = repo[node1]
589 ctx2 = repo[node2]
589 ctx2 = repo[node2]
590 for subpath, sub in subrepo.itersubrepos(ctx1, ctx2):
590 for subpath, sub in subrepo.itersubrepos(ctx1, ctx2):
591 tempnode2 = node2
591 tempnode2 = node2
592 try:
592 try:
593 if node2 is not None:
593 if node2 is not None:
594 tempnode2 = ctx2.substate[subpath][1]
594 tempnode2 = ctx2.substate[subpath][1]
595 except KeyError:
595 except KeyError:
596 # A subrepo that existed in node1 was deleted between node1 and
596 # A subrepo that existed in node1 was deleted between node1 and
597 # node2 (inclusive). Thus, ctx2's substate won't contain that
597 # node2 (inclusive). Thus, ctx2's substate won't contain that
598 # subpath. The best we can do is to ignore it.
598 # subpath. The best we can do is to ignore it.
599 tempnode2 = None
599 tempnode2 = None
600 submatch = matchmod.narrowmatcher(subpath, match)
600 submatch = matchmod.narrowmatcher(subpath, match)
601 sub.diff(diffopts, tempnode2, submatch, changes=changes,
601 sub.diff(diffopts, tempnode2, submatch, changes=changes,
602 stat=stat, fp=fp, prefix=prefix)
602 stat=stat, fp=fp, prefix=prefix)
603
603
604 class changeset_printer(object):
604 class changeset_printer(object):
605 '''show changeset information when templating not requested.'''
605 '''show changeset information when templating not requested.'''
606
606
607 def __init__(self, ui, repo, patch, diffopts, buffered):
607 def __init__(self, ui, repo, patch, diffopts, buffered):
608 self.ui = ui
608 self.ui = ui
609 self.repo = repo
609 self.repo = repo
610 self.buffered = buffered
610 self.buffered = buffered
611 self.patch = patch
611 self.patch = patch
612 self.diffopts = diffopts
612 self.diffopts = diffopts
613 self.header = {}
613 self.header = {}
614 self.hunk = {}
614 self.hunk = {}
615 self.lastheader = None
615 self.lastheader = None
616 self.footer = None
616 self.footer = None
617
617
618 def flush(self, rev):
618 def flush(self, rev):
619 if rev in self.header:
619 if rev in self.header:
620 h = self.header[rev]
620 h = self.header[rev]
621 if h != self.lastheader:
621 if h != self.lastheader:
622 self.lastheader = h
622 self.lastheader = h
623 self.ui.write(h)
623 self.ui.write(h)
624 del self.header[rev]
624 del self.header[rev]
625 if rev in self.hunk:
625 if rev in self.hunk:
626 self.ui.write(self.hunk[rev])
626 self.ui.write(self.hunk[rev])
627 del self.hunk[rev]
627 del self.hunk[rev]
628 return 1
628 return 1
629 return 0
629 return 0
630
630
631 def close(self):
631 def close(self):
632 if self.footer:
632 if self.footer:
633 self.ui.write(self.footer)
633 self.ui.write(self.footer)
634
634
635 def show(self, ctx, copies=None, matchfn=None, **props):
635 def show(self, ctx, copies=None, matchfn=None, **props):
636 if self.buffered:
636 if self.buffered:
637 self.ui.pushbuffer()
637 self.ui.pushbuffer()
638 self._show(ctx, copies, matchfn, props)
638 self._show(ctx, copies, matchfn, props)
639 self.hunk[ctx.rev()] = self.ui.popbuffer(labeled=True)
639 self.hunk[ctx.rev()] = self.ui.popbuffer(labeled=True)
640 else:
640 else:
641 self._show(ctx, copies, matchfn, props)
641 self._show(ctx, copies, matchfn, props)
642
642
643 def _show(self, ctx, copies, matchfn, props):
643 def _show(self, ctx, copies, matchfn, props):
644 '''show a single changeset or file revision'''
644 '''show a single changeset or file revision'''
645 changenode = ctx.node()
645 changenode = ctx.node()
646 rev = ctx.rev()
646 rev = ctx.rev()
647
647
648 if self.ui.quiet:
648 if self.ui.quiet:
649 self.ui.write("%d:%s\n" % (rev, short(changenode)),
649 self.ui.write("%d:%s\n" % (rev, short(changenode)),
650 label='log.node')
650 label='log.node')
651 return
651 return
652
652
653 log = self.repo.changelog
653 log = self.repo.changelog
654 date = util.datestr(ctx.date())
654 date = util.datestr(ctx.date())
655
655
656 hexfunc = self.ui.debugflag and hex or short
656 hexfunc = self.ui.debugflag and hex or short
657
657
658 parents = [(p, hexfunc(log.node(p)))
658 parents = [(p, hexfunc(log.node(p)))
659 for p in self._meaningful_parentrevs(log, rev)]
659 for p in self._meaningful_parentrevs(log, rev)]
660
660
661 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)),
661 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)),
662 label='log.changeset')
662 label='log.changeset')
663
663
664 branch = ctx.branch()
664 branch = ctx.branch()
665 # don't show the default branch name
665 # don't show the default branch name
666 if branch != 'default':
666 if branch != 'default':
667 self.ui.write(_("branch: %s\n") % branch,
667 self.ui.write(_("branch: %s\n") % branch,
668 label='log.branch')
668 label='log.branch')
669 for bookmark in self.repo.nodebookmarks(changenode):
669 for bookmark in self.repo.nodebookmarks(changenode):
670 self.ui.write(_("bookmark: %s\n") % bookmark,
670 self.ui.write(_("bookmark: %s\n") % bookmark,
671 label='log.bookmark')
671 label='log.bookmark')
672 for tag in self.repo.nodetags(changenode):
672 for tag in self.repo.nodetags(changenode):
673 self.ui.write(_("tag: %s\n") % tag,
673 self.ui.write(_("tag: %s\n") % tag,
674 label='log.tag')
674 label='log.tag')
675 if self.ui.debugflag and ctx.phase():
675 if self.ui.debugflag and ctx.phase():
676 self.ui.write(_("phase: %s\n") % _(ctx.phasestr()),
676 self.ui.write(_("phase: %s\n") % _(ctx.phasestr()),
677 label='log.phase')
677 label='log.phase')
678 for parent in parents:
678 for parent in parents:
679 self.ui.write(_("parent: %d:%s\n") % parent,
679 self.ui.write(_("parent: %d:%s\n") % parent,
680 label='log.parent')
680 label='log.parent')
681
681
682 if self.ui.debugflag:
682 if self.ui.debugflag:
683 mnode = ctx.manifestnode()
683 mnode = ctx.manifestnode()
684 self.ui.write(_("manifest: %d:%s\n") %
684 self.ui.write(_("manifest: %d:%s\n") %
685 (self.repo.manifest.rev(mnode), hex(mnode)),
685 (self.repo.manifest.rev(mnode), hex(mnode)),
686 label='ui.debug log.manifest')
686 label='ui.debug log.manifest')
687 self.ui.write(_("user: %s\n") % ctx.user(),
687 self.ui.write(_("user: %s\n") % ctx.user(),
688 label='log.user')
688 label='log.user')
689 self.ui.write(_("date: %s\n") % date,
689 self.ui.write(_("date: %s\n") % date,
690 label='log.date')
690 label='log.date')
691
691
692 if self.ui.debugflag:
692 if self.ui.debugflag:
693 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
693 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
694 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
694 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
695 files):
695 files):
696 if value:
696 if value:
697 self.ui.write("%-12s %s\n" % (key, " ".join(value)),
697 self.ui.write("%-12s %s\n" % (key, " ".join(value)),
698 label='ui.debug log.files')
698 label='ui.debug log.files')
699 elif ctx.files() and self.ui.verbose:
699 elif ctx.files() and self.ui.verbose:
700 self.ui.write(_("files: %s\n") % " ".join(ctx.files()),
700 self.ui.write(_("files: %s\n") % " ".join(ctx.files()),
701 label='ui.note log.files')
701 label='ui.note log.files')
702 if copies and self.ui.verbose:
702 if copies and self.ui.verbose:
703 copies = ['%s (%s)' % c for c in copies]
703 copies = ['%s (%s)' % c for c in copies]
704 self.ui.write(_("copies: %s\n") % ' '.join(copies),
704 self.ui.write(_("copies: %s\n") % ' '.join(copies),
705 label='ui.note log.copies')
705 label='ui.note log.copies')
706
706
707 extra = ctx.extra()
707 extra = ctx.extra()
708 if extra and self.ui.debugflag:
708 if extra and self.ui.debugflag:
709 for key, value in sorted(extra.items()):
709 for key, value in sorted(extra.items()):
710 self.ui.write(_("extra: %s=%s\n")
710 self.ui.write(_("extra: %s=%s\n")
711 % (key, value.encode('string_escape')),
711 % (key, value.encode('string_escape')),
712 label='ui.debug log.extra')
712 label='ui.debug log.extra')
713
713
714 description = ctx.description().strip()
714 description = ctx.description().strip()
715 if description:
715 if description:
716 if self.ui.verbose:
716 if self.ui.verbose:
717 self.ui.write(_("description:\n"),
717 self.ui.write(_("description:\n"),
718 label='ui.note log.description')
718 label='ui.note log.description')
719 self.ui.write(description,
719 self.ui.write(description,
720 label='ui.note log.description')
720 label='ui.note log.description')
721 self.ui.write("\n\n")
721 self.ui.write("\n\n")
722 else:
722 else:
723 self.ui.write(_("summary: %s\n") %
723 self.ui.write(_("summary: %s\n") %
724 description.splitlines()[0],
724 description.splitlines()[0],
725 label='log.summary')
725 label='log.summary')
726 self.ui.write("\n")
726 self.ui.write("\n")
727
727
728 self.showpatch(changenode, matchfn)
728 self.showpatch(changenode, matchfn)
729
729
730 def showpatch(self, node, matchfn):
730 def showpatch(self, node, matchfn):
731 if not matchfn:
731 if not matchfn:
732 matchfn = self.patch
732 matchfn = self.patch
733 if matchfn:
733 if matchfn:
734 stat = self.diffopts.get('stat')
734 stat = self.diffopts.get('stat')
735 diff = self.diffopts.get('patch')
735 diff = self.diffopts.get('patch')
736 diffopts = patch.diffopts(self.ui, self.diffopts)
736 diffopts = patch.diffopts(self.ui, self.diffopts)
737 prev = self.repo.changelog.parents(node)[0]
737 prev = self.repo.changelog.parents(node)[0]
738 if stat:
738 if stat:
739 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
739 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
740 match=matchfn, stat=True)
740 match=matchfn, stat=True)
741 if diff:
741 if diff:
742 if stat:
742 if stat:
743 self.ui.write("\n")
743 self.ui.write("\n")
744 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
744 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
745 match=matchfn, stat=False)
745 match=matchfn, stat=False)
746 self.ui.write("\n")
746 self.ui.write("\n")
747
747
748 def _meaningful_parentrevs(self, log, rev):
748 def _meaningful_parentrevs(self, log, rev):
749 """Return list of meaningful (or all if debug) parentrevs for rev.
749 """Return list of meaningful (or all if debug) parentrevs for rev.
750
750
751 For merges (two non-nullrev revisions) both parents are meaningful.
751 For merges (two non-nullrev revisions) both parents are meaningful.
752 Otherwise the first parent revision is considered meaningful if it
752 Otherwise the first parent revision is considered meaningful if it
753 is not the preceding revision.
753 is not the preceding revision.
754 """
754 """
755 parents = log.parentrevs(rev)
755 parents = log.parentrevs(rev)
756 if not self.ui.debugflag and parents[1] == nullrev:
756 if not self.ui.debugflag and parents[1] == nullrev:
757 if parents[0] >= rev - 1:
757 if parents[0] >= rev - 1:
758 parents = []
758 parents = []
759 else:
759 else:
760 parents = [parents[0]]
760 parents = [parents[0]]
761 return parents
761 return parents
762
762
763
763
764 class changeset_templater(changeset_printer):
764 class changeset_templater(changeset_printer):
765 '''format changeset information.'''
765 '''format changeset information.'''
766
766
767 def __init__(self, ui, repo, patch, diffopts, mapfile, buffered):
767 def __init__(self, ui, repo, patch, diffopts, mapfile, buffered):
768 changeset_printer.__init__(self, ui, repo, patch, diffopts, buffered)
768 changeset_printer.__init__(self, ui, repo, patch, diffopts, buffered)
769 formatnode = ui.debugflag and (lambda x: x) or (lambda x: x[:12])
769 formatnode = ui.debugflag and (lambda x: x) or (lambda x: x[:12])
770 defaulttempl = {
770 defaulttempl = {
771 'parent': '{rev}:{node|formatnode} ',
771 'parent': '{rev}:{node|formatnode} ',
772 'manifest': '{rev}:{node|formatnode}',
772 'manifest': '{rev}:{node|formatnode}',
773 'file_copy': '{name} ({source})',
773 'file_copy': '{name} ({source})',
774 'extra': '{key}={value|stringescape}'
774 'extra': '{key}={value|stringescape}'
775 }
775 }
776 # filecopy is preserved for compatibility reasons
776 # filecopy is preserved for compatibility reasons
777 defaulttempl['filecopy'] = defaulttempl['file_copy']
777 defaulttempl['filecopy'] = defaulttempl['file_copy']
778 self.t = templater.templater(mapfile, {'formatnode': formatnode},
778 self.t = templater.templater(mapfile, {'formatnode': formatnode},
779 cache=defaulttempl)
779 cache=defaulttempl)
780 self.cache = {}
780 self.cache = {}
781
781
782 def use_template(self, t):
782 def use_template(self, t):
783 '''set template string to use'''
783 '''set template string to use'''
784 self.t.cache['changeset'] = t
784 self.t.cache['changeset'] = t
785
785
786 def _meaningful_parentrevs(self, ctx):
786 def _meaningful_parentrevs(self, ctx):
787 """Return list of meaningful (or all if debug) parentrevs for rev.
787 """Return list of meaningful (or all if debug) parentrevs for rev.
788 """
788 """
789 parents = ctx.parents()
789 parents = ctx.parents()
790 if len(parents) > 1:
790 if len(parents) > 1:
791 return parents
791 return parents
792 if self.ui.debugflag:
792 if self.ui.debugflag:
793 return [parents[0], self.repo['null']]
793 return [parents[0], self.repo['null']]
794 if parents[0].rev() >= ctx.rev() - 1:
794 if parents[0].rev() >= ctx.rev() - 1:
795 return []
795 return []
796 return parents
796 return parents
797
797
798 def _show(self, ctx, copies, matchfn, props):
798 def _show(self, ctx, copies, matchfn, props):
799 '''show a single changeset or file revision'''
799 '''show a single changeset or file revision'''
800
800
801 showlist = templatekw.showlist
801 showlist = templatekw.showlist
802
802
803 # showparents() behaviour depends on ui trace level which
803 # showparents() behaviour depends on ui trace level which
804 # causes unexpected behaviours at templating level and makes
804 # causes unexpected behaviours at templating level and makes
805 # it harder to extract it in a standalone function. Its
805 # it harder to extract it in a standalone function. Its
806 # behaviour cannot be changed so leave it here for now.
806 # behaviour cannot be changed so leave it here for now.
807 def showparents(**args):
807 def showparents(**args):
808 ctx = args['ctx']
808 ctx = args['ctx']
809 parents = [[('rev', p.rev()), ('node', p.hex())]
809 parents = [[('rev', p.rev()), ('node', p.hex())]
810 for p in self._meaningful_parentrevs(ctx)]
810 for p in self._meaningful_parentrevs(ctx)]
811 return showlist('parent', parents, **args)
811 return showlist('parent', parents, **args)
812
812
813 props = props.copy()
813 props = props.copy()
814 props.update(templatekw.keywords)
814 props.update(templatekw.keywords)
815 props['parents'] = showparents
815 props['parents'] = showparents
816 props['templ'] = self.t
816 props['templ'] = self.t
817 props['ctx'] = ctx
817 props['ctx'] = ctx
818 props['repo'] = self.repo
818 props['repo'] = self.repo
819 props['revcache'] = {'copies': copies}
819 props['revcache'] = {'copies': copies}
820 props['cache'] = self.cache
820 props['cache'] = self.cache
821
821
822 # find correct templates for current mode
822 # find correct templates for current mode
823
823
824 tmplmodes = [
824 tmplmodes = [
825 (True, None),
825 (True, None),
826 (self.ui.verbose, 'verbose'),
826 (self.ui.verbose, 'verbose'),
827 (self.ui.quiet, 'quiet'),
827 (self.ui.quiet, 'quiet'),
828 (self.ui.debugflag, 'debug'),
828 (self.ui.debugflag, 'debug'),
829 ]
829 ]
830
830
831 types = {'header': '', 'footer':'', 'changeset': 'changeset'}
831 types = {'header': '', 'footer':'', 'changeset': 'changeset'}
832 for mode, postfix in tmplmodes:
832 for mode, postfix in tmplmodes:
833 for type in types:
833 for type in types:
834 cur = postfix and ('%s_%s' % (type, postfix)) or type
834 cur = postfix and ('%s_%s' % (type, postfix)) or type
835 if mode and cur in self.t:
835 if mode and cur in self.t:
836 types[type] = cur
836 types[type] = cur
837
837
838 try:
838 try:
839
839
840 # write header
840 # write header
841 if types['header']:
841 if types['header']:
842 h = templater.stringify(self.t(types['header'], **props))
842 h = templater.stringify(self.t(types['header'], **props))
843 if self.buffered:
843 if self.buffered:
844 self.header[ctx.rev()] = h
844 self.header[ctx.rev()] = h
845 else:
845 else:
846 if self.lastheader != h:
846 if self.lastheader != h:
847 self.lastheader = h
847 self.lastheader = h
848 self.ui.write(h)
848 self.ui.write(h)
849
849
850 # write changeset metadata, then patch if requested
850 # write changeset metadata, then patch if requested
851 key = types['changeset']
851 key = types['changeset']
852 self.ui.write(templater.stringify(self.t(key, **props)))
852 self.ui.write(templater.stringify(self.t(key, **props)))
853 self.showpatch(ctx.node(), matchfn)
853 self.showpatch(ctx.node(), matchfn)
854
854
855 if types['footer']:
855 if types['footer']:
856 if not self.footer:
856 if not self.footer:
857 self.footer = templater.stringify(self.t(types['footer'],
857 self.footer = templater.stringify(self.t(types['footer'],
858 **props))
858 **props))
859
859
860 except KeyError, inst:
860 except KeyError, inst:
861 msg = _("%s: no key named '%s'")
861 msg = _("%s: no key named '%s'")
862 raise util.Abort(msg % (self.t.mapfile, inst.args[0]))
862 raise util.Abort(msg % (self.t.mapfile, inst.args[0]))
863 except SyntaxError, inst:
863 except SyntaxError, inst:
864 raise util.Abort('%s: %s' % (self.t.mapfile, inst.args[0]))
864 raise util.Abort('%s: %s' % (self.t.mapfile, inst.args[0]))
865
865
866 def show_changeset(ui, repo, opts, buffered=False):
866 def show_changeset(ui, repo, opts, buffered=False):
867 """show one changeset using template or regular display.
867 """show one changeset using template or regular display.
868
868
869 Display format will be the first non-empty hit of:
869 Display format will be the first non-empty hit of:
870 1. option 'template'
870 1. option 'template'
871 2. option 'style'
871 2. option 'style'
872 3. [ui] setting 'logtemplate'
872 3. [ui] setting 'logtemplate'
873 4. [ui] setting 'style'
873 4. [ui] setting 'style'
874 If all of these values are either the unset or the empty string,
874 If all of these values are either the unset or the empty string,
875 regular display via changeset_printer() is done.
875 regular display via changeset_printer() is done.
876 """
876 """
877 # options
877 # options
878 patch = False
878 patch = False
879 if opts.get('patch') or opts.get('stat'):
879 if opts.get('patch') or opts.get('stat'):
880 patch = scmutil.matchall(repo)
880 patch = scmutil.matchall(repo)
881
881
882 tmpl = opts.get('template')
882 tmpl = opts.get('template')
883 style = None
883 style = None
884 if tmpl:
884 if tmpl:
885 tmpl = templater.parsestring(tmpl, quoted=False)
885 tmpl = templater.parsestring(tmpl, quoted=False)
886 else:
886 else:
887 style = opts.get('style')
887 style = opts.get('style')
888
888
889 # ui settings
889 # ui settings
890 if not (tmpl or style):
890 if not (tmpl or style):
891 tmpl = ui.config('ui', 'logtemplate')
891 tmpl = ui.config('ui', 'logtemplate')
892 if tmpl:
892 if tmpl:
893 tmpl = templater.parsestring(tmpl)
893 tmpl = templater.parsestring(tmpl)
894 else:
894 else:
895 style = util.expandpath(ui.config('ui', 'style', ''))
895 style = util.expandpath(ui.config('ui', 'style', ''))
896
896
897 if not (tmpl or style):
897 if not (tmpl or style):
898 return changeset_printer(ui, repo, patch, opts, buffered)
898 return changeset_printer(ui, repo, patch, opts, buffered)
899
899
900 mapfile = None
900 mapfile = None
901 if style and not tmpl:
901 if style and not tmpl:
902 mapfile = style
902 mapfile = style
903 if not os.path.split(mapfile)[0]:
903 if not os.path.split(mapfile)[0]:
904 mapname = (templater.templatepath('map-cmdline.' + mapfile)
904 mapname = (templater.templatepath('map-cmdline.' + mapfile)
905 or templater.templatepath(mapfile))
905 or templater.templatepath(mapfile))
906 if mapname:
906 if mapname:
907 mapfile = mapname
907 mapfile = mapname
908
908
909 try:
909 try:
910 t = changeset_templater(ui, repo, patch, opts, mapfile, buffered)
910 t = changeset_templater(ui, repo, patch, opts, mapfile, buffered)
911 except SyntaxError, inst:
911 except SyntaxError, inst:
912 raise util.Abort(inst.args[0])
912 raise util.Abort(inst.args[0])
913 if tmpl:
913 if tmpl:
914 t.use_template(tmpl)
914 t.use_template(tmpl)
915 return t
915 return t
916
916
917 def finddate(ui, repo, date):
917 def finddate(ui, repo, date):
918 """Find the tipmost changeset that matches the given date spec"""
918 """Find the tipmost changeset that matches the given date spec"""
919
919
920 df = util.matchdate(date)
920 df = util.matchdate(date)
921 m = scmutil.matchall(repo)
921 m = scmutil.matchall(repo)
922 results = {}
922 results = {}
923
923
924 def prep(ctx, fns):
924 def prep(ctx, fns):
925 d = ctx.date()
925 d = ctx.date()
926 if df(d[0]):
926 if df(d[0]):
927 results[ctx.rev()] = d
927 results[ctx.rev()] = d
928
928
929 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
929 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
930 rev = ctx.rev()
930 rev = ctx.rev()
931 if rev in results:
931 if rev in results:
932 ui.status(_("Found revision %s from %s\n") %
932 ui.status(_("Found revision %s from %s\n") %
933 (rev, util.datestr(results[rev])))
933 (rev, util.datestr(results[rev])))
934 return str(rev)
934 return str(rev)
935
935
936 raise util.Abort(_("revision matching date not found"))
936 raise util.Abort(_("revision matching date not found"))
937
937
938 def walkchangerevs(repo, match, opts, prepare):
938 def walkchangerevs(repo, match, opts, prepare):
939 '''Iterate over files and the revs in which they changed.
939 '''Iterate over files and the revs in which they changed.
940
940
941 Callers most commonly need to iterate backwards over the history
941 Callers most commonly need to iterate backwards over the history
942 in which they are interested. Doing so has awful (quadratic-looking)
942 in which they are interested. Doing so has awful (quadratic-looking)
943 performance, so we use iterators in a "windowed" way.
943 performance, so we use iterators in a "windowed" way.
944
944
945 We walk a window of revisions in the desired order. Within the
945 We walk a window of revisions in the desired order. Within the
946 window, we first walk forwards to gather data, then in the desired
946 window, we first walk forwards to gather data, then in the desired
947 order (usually backwards) to display it.
947 order (usually backwards) to display it.
948
948
949 This function returns an iterator yielding contexts. Before
949 This function returns an iterator yielding contexts. Before
950 yielding each context, the iterator will first call the prepare
950 yielding each context, the iterator will first call the prepare
951 function on each context in the window in forward order.'''
951 function on each context in the window in forward order.'''
952
952
953 def increasing_windows(start, end, windowsize=8, sizelimit=512):
953 def increasing_windows(start, end, windowsize=8, sizelimit=512):
954 if start < end:
954 if start < end:
955 while start < end:
955 while start < end:
956 yield start, min(windowsize, end - start)
956 yield start, min(windowsize, end - start)
957 start += windowsize
957 start += windowsize
958 if windowsize < sizelimit:
958 if windowsize < sizelimit:
959 windowsize *= 2
959 windowsize *= 2
960 else:
960 else:
961 while start > end:
961 while start > end:
962 yield start, min(windowsize, start - end - 1)
962 yield start, min(windowsize, start - end - 1)
963 start -= windowsize
963 start -= windowsize
964 if windowsize < sizelimit:
964 if windowsize < sizelimit:
965 windowsize *= 2
965 windowsize *= 2
966
966
967 follow = opts.get('follow') or opts.get('follow_first')
967 follow = opts.get('follow') or opts.get('follow_first')
968
968
969 if not len(repo):
969 if not len(repo):
970 return []
970 return []
971
971
972 if follow:
972 if follow:
973 defrange = '%s:0' % repo['.'].rev()
973 defrange = '%s:0' % repo['.'].rev()
974 else:
974 else:
975 defrange = '-1:0'
975 defrange = '-1:0'
976 revs = scmutil.revrange(repo, opts['rev'] or [defrange])
976 revs = scmutil.revrange(repo, opts['rev'] or [defrange])
977 if not revs:
977 if not revs:
978 return []
978 return []
979 wanted = set()
979 wanted = set()
980 slowpath = match.anypats() or (match.files() and opts.get('removed'))
980 slowpath = match.anypats() or (match.files() and opts.get('removed'))
981 fncache = {}
981 fncache = {}
982 change = repo.changectx
982 change = repo.changectx
983
983
984 # First step is to fill wanted, the set of revisions that we want to yield.
984 # First step is to fill wanted, the set of revisions that we want to yield.
985 # When it does not induce extra cost, we also fill fncache for revisions in
985 # When it does not induce extra cost, we also fill fncache for revisions in
986 # wanted: a cache of filenames that were changed (ctx.files()) and that
986 # wanted: a cache of filenames that were changed (ctx.files()) and that
987 # match the file filtering conditions.
987 # match the file filtering conditions.
988
988
989 if not slowpath and not match.files():
989 if not slowpath and not match.files():
990 # No files, no patterns. Display all revs.
990 # No files, no patterns. Display all revs.
991 wanted = set(revs)
991 wanted = set(revs)
992 copies = []
992 copies = []
993
993
994 if not slowpath:
994 if not slowpath:
995 # We only have to read through the filelog to find wanted revisions
995 # We only have to read through the filelog to find wanted revisions
996
996
997 minrev, maxrev = min(revs), max(revs)
997 minrev, maxrev = min(revs), max(revs)
998 def filerevgen(filelog, last):
998 def filerevgen(filelog, last):
999 """
999 """
1000 Only files, no patterns. Check the history of each file.
1000 Only files, no patterns. Check the history of each file.
1001
1001
1002 Examines filelog entries within minrev, maxrev linkrev range
1002 Examines filelog entries within minrev, maxrev linkrev range
1003 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
1003 Returns an iterator yielding (linkrev, parentlinkrevs, copied)
1004 tuples in backwards order
1004 tuples in backwards order
1005 """
1005 """
1006 cl_count = len(repo)
1006 cl_count = len(repo)
1007 revs = []
1007 revs = []
1008 for j in xrange(0, last + 1):
1008 for j in xrange(0, last + 1):
1009 linkrev = filelog.linkrev(j)
1009 linkrev = filelog.linkrev(j)
1010 if linkrev < minrev:
1010 if linkrev < minrev:
1011 continue
1011 continue
1012 # only yield rev for which we have the changelog, it can
1012 # only yield rev for which we have the changelog, it can
1013 # happen while doing "hg log" during a pull or commit
1013 # happen while doing "hg log" during a pull or commit
1014 if linkrev >= cl_count:
1014 if linkrev >= cl_count:
1015 break
1015 break
1016
1016
1017 parentlinkrevs = []
1017 parentlinkrevs = []
1018 for p in filelog.parentrevs(j):
1018 for p in filelog.parentrevs(j):
1019 if p != nullrev:
1019 if p != nullrev:
1020 parentlinkrevs.append(filelog.linkrev(p))
1020 parentlinkrevs.append(filelog.linkrev(p))
1021 n = filelog.node(j)
1021 n = filelog.node(j)
1022 revs.append((linkrev, parentlinkrevs,
1022 revs.append((linkrev, parentlinkrevs,
1023 follow and filelog.renamed(n)))
1023 follow and filelog.renamed(n)))
1024
1024
1025 return reversed(revs)
1025 return reversed(revs)
1026 def iterfiles():
1026 def iterfiles():
1027 pctx = repo['.']
1027 for filename in match.files():
1028 for filename in match.files():
1028 yield filename, None
1029 if follow:
1030 if filename not in pctx:
1031 raise util.Abort(_('cannot follow file not in parent '
1032 'revision: "%s"') % filename)
1033 yield filename, pctx[filename].filenode()
1034 else:
1035 yield filename, None
1029 for filename_node in copies:
1036 for filename_node in copies:
1030 yield filename_node
1037 yield filename_node
1031 for file_, node in iterfiles():
1038 for file_, node in iterfiles():
1032 filelog = repo.file(file_)
1039 filelog = repo.file(file_)
1033 if not len(filelog):
1040 if not len(filelog):
1034 if node is None:
1041 if node is None:
1035 # A zero count may be a directory or deleted file, so
1042 # A zero count may be a directory or deleted file, so
1036 # try to find matching entries on the slow path.
1043 # try to find matching entries on the slow path.
1037 if follow:
1044 if follow:
1038 raise util.Abort(
1045 raise util.Abort(
1039 _('cannot follow nonexistent file: "%s"') % file_)
1046 _('cannot follow nonexistent file: "%s"') % file_)
1040 slowpath = True
1047 slowpath = True
1041 break
1048 break
1042 else:
1049 else:
1043 continue
1050 continue
1044
1051
1045 if node is None:
1052 if node is None:
1046 last = len(filelog) - 1
1053 last = len(filelog) - 1
1047 else:
1054 else:
1048 last = filelog.rev(node)
1055 last = filelog.rev(node)
1049
1056
1050
1057
1051 # keep track of all ancestors of the file
1058 # keep track of all ancestors of the file
1052 ancestors = set([filelog.linkrev(last)])
1059 ancestors = set([filelog.linkrev(last)])
1053
1060
1054 # iterate from latest to oldest revision
1061 # iterate from latest to oldest revision
1055 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
1062 for rev, flparentlinkrevs, copied in filerevgen(filelog, last):
1056 if not follow:
1063 if not follow:
1057 if rev > maxrev:
1064 if rev > maxrev:
1058 continue
1065 continue
1059 else:
1066 else:
1060 # Note that last might not be the first interesting
1067 # Note that last might not be the first interesting
1061 # rev to us:
1068 # rev to us:
1062 # if the file has been changed after maxrev, we'll
1069 # if the file has been changed after maxrev, we'll
1063 # have linkrev(last) > maxrev, and we still need
1070 # have linkrev(last) > maxrev, and we still need
1064 # to explore the file graph
1071 # to explore the file graph
1065 if rev not in ancestors:
1072 if rev not in ancestors:
1066 continue
1073 continue
1067 # XXX insert 1327 fix here
1074 # XXX insert 1327 fix here
1068 if flparentlinkrevs:
1075 if flparentlinkrevs:
1069 ancestors.update(flparentlinkrevs)
1076 ancestors.update(flparentlinkrevs)
1070
1077
1071 fncache.setdefault(rev, []).append(file_)
1078 fncache.setdefault(rev, []).append(file_)
1072 wanted.add(rev)
1079 wanted.add(rev)
1073 if copied:
1080 if copied:
1074 copies.append(copied)
1081 copies.append(copied)
1075 if slowpath:
1082 if slowpath:
1076 # We have to read the changelog to match filenames against
1083 # We have to read the changelog to match filenames against
1077 # changed files
1084 # changed files
1078
1085
1079 if follow:
1086 if follow:
1080 raise util.Abort(_('can only follow copies/renames for explicit '
1087 raise util.Abort(_('can only follow copies/renames for explicit '
1081 'filenames'))
1088 'filenames'))
1082
1089
1083 # The slow path checks files modified in every changeset.
1090 # The slow path checks files modified in every changeset.
1084 for i in sorted(revs):
1091 for i in sorted(revs):
1085 ctx = change(i)
1092 ctx = change(i)
1086 matches = filter(match, ctx.files())
1093 matches = filter(match, ctx.files())
1087 if matches:
1094 if matches:
1088 fncache[i] = matches
1095 fncache[i] = matches
1089 wanted.add(i)
1096 wanted.add(i)
1090
1097
1091 class followfilter(object):
1098 class followfilter(object):
1092 def __init__(self, onlyfirst=False):
1099 def __init__(self, onlyfirst=False):
1093 self.startrev = nullrev
1100 self.startrev = nullrev
1094 self.roots = set()
1101 self.roots = set()
1095 self.onlyfirst = onlyfirst
1102 self.onlyfirst = onlyfirst
1096
1103
1097 def match(self, rev):
1104 def match(self, rev):
1098 def realparents(rev):
1105 def realparents(rev):
1099 if self.onlyfirst:
1106 if self.onlyfirst:
1100 return repo.changelog.parentrevs(rev)[0:1]
1107 return repo.changelog.parentrevs(rev)[0:1]
1101 else:
1108 else:
1102 return filter(lambda x: x != nullrev,
1109 return filter(lambda x: x != nullrev,
1103 repo.changelog.parentrevs(rev))
1110 repo.changelog.parentrevs(rev))
1104
1111
1105 if self.startrev == nullrev:
1112 if self.startrev == nullrev:
1106 self.startrev = rev
1113 self.startrev = rev
1107 return True
1114 return True
1108
1115
1109 if rev > self.startrev:
1116 if rev > self.startrev:
1110 # forward: all descendants
1117 # forward: all descendants
1111 if not self.roots:
1118 if not self.roots:
1112 self.roots.add(self.startrev)
1119 self.roots.add(self.startrev)
1113 for parent in realparents(rev):
1120 for parent in realparents(rev):
1114 if parent in self.roots:
1121 if parent in self.roots:
1115 self.roots.add(rev)
1122 self.roots.add(rev)
1116 return True
1123 return True
1117 else:
1124 else:
1118 # backwards: all parents
1125 # backwards: all parents
1119 if not self.roots:
1126 if not self.roots:
1120 self.roots.update(realparents(self.startrev))
1127 self.roots.update(realparents(self.startrev))
1121 if rev in self.roots:
1128 if rev in self.roots:
1122 self.roots.remove(rev)
1129 self.roots.remove(rev)
1123 self.roots.update(realparents(rev))
1130 self.roots.update(realparents(rev))
1124 return True
1131 return True
1125
1132
1126 return False
1133 return False
1127
1134
1128 # it might be worthwhile to do this in the iterator if the rev range
1135 # it might be worthwhile to do this in the iterator if the rev range
1129 # is descending and the prune args are all within that range
1136 # is descending and the prune args are all within that range
1130 for rev in opts.get('prune', ()):
1137 for rev in opts.get('prune', ()):
1131 rev = repo.changelog.rev(repo.lookup(rev))
1138 rev = repo.changelog.rev(repo.lookup(rev))
1132 ff = followfilter()
1139 ff = followfilter()
1133 stop = min(revs[0], revs[-1])
1140 stop = min(revs[0], revs[-1])
1134 for x in xrange(rev, stop - 1, -1):
1141 for x in xrange(rev, stop - 1, -1):
1135 if ff.match(x):
1142 if ff.match(x):
1136 wanted.discard(x)
1143 wanted.discard(x)
1137
1144
1138 # Now that wanted is correctly initialized, we can iterate over the
1145 # Now that wanted is correctly initialized, we can iterate over the
1139 # revision range, yielding only revisions in wanted.
1146 # revision range, yielding only revisions in wanted.
1140 def iterate():
1147 def iterate():
1141 if follow and not match.files():
1148 if follow and not match.files():
1142 ff = followfilter(onlyfirst=opts.get('follow_first'))
1149 ff = followfilter(onlyfirst=opts.get('follow_first'))
1143 def want(rev):
1150 def want(rev):
1144 return ff.match(rev) and rev in wanted
1151 return ff.match(rev) and rev in wanted
1145 else:
1152 else:
1146 def want(rev):
1153 def want(rev):
1147 return rev in wanted
1154 return rev in wanted
1148
1155
1149 for i, window in increasing_windows(0, len(revs)):
1156 for i, window in increasing_windows(0, len(revs)):
1150 nrevs = [rev for rev in revs[i:i + window] if want(rev)]
1157 nrevs = [rev for rev in revs[i:i + window] if want(rev)]
1151 for rev in sorted(nrevs):
1158 for rev in sorted(nrevs):
1152 fns = fncache.get(rev)
1159 fns = fncache.get(rev)
1153 ctx = change(rev)
1160 ctx = change(rev)
1154 if not fns:
1161 if not fns:
1155 def fns_generator():
1162 def fns_generator():
1156 for f in ctx.files():
1163 for f in ctx.files():
1157 if match(f):
1164 if match(f):
1158 yield f
1165 yield f
1159 fns = fns_generator()
1166 fns = fns_generator()
1160 prepare(ctx, fns)
1167 prepare(ctx, fns)
1161 for rev in nrevs:
1168 for rev in nrevs:
1162 yield change(rev)
1169 yield change(rev)
1163 return iterate()
1170 return iterate()
1164
1171
1165 def add(ui, repo, match, dryrun, listsubrepos, prefix, explicitonly):
1172 def add(ui, repo, match, dryrun, listsubrepos, prefix, explicitonly):
1166 join = lambda f: os.path.join(prefix, f)
1173 join = lambda f: os.path.join(prefix, f)
1167 bad = []
1174 bad = []
1168 oldbad = match.bad
1175 oldbad = match.bad
1169 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1176 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1170 names = []
1177 names = []
1171 wctx = repo[None]
1178 wctx = repo[None]
1172 cca = None
1179 cca = None
1173 abort, warn = scmutil.checkportabilityalert(ui)
1180 abort, warn = scmutil.checkportabilityalert(ui)
1174 if abort or warn:
1181 if abort or warn:
1175 cca = scmutil.casecollisionauditor(ui, abort, wctx)
1182 cca = scmutil.casecollisionauditor(ui, abort, wctx)
1176 for f in repo.walk(match):
1183 for f in repo.walk(match):
1177 exact = match.exact(f)
1184 exact = match.exact(f)
1178 if exact or not explicitonly and f not in repo.dirstate:
1185 if exact or not explicitonly and f not in repo.dirstate:
1179 if cca:
1186 if cca:
1180 cca(f)
1187 cca(f)
1181 names.append(f)
1188 names.append(f)
1182 if ui.verbose or not exact:
1189 if ui.verbose or not exact:
1183 ui.status(_('adding %s\n') % match.rel(join(f)))
1190 ui.status(_('adding %s\n') % match.rel(join(f)))
1184
1191
1185 for subpath in wctx.substate:
1192 for subpath in wctx.substate:
1186 sub = wctx.sub(subpath)
1193 sub = wctx.sub(subpath)
1187 try:
1194 try:
1188 submatch = matchmod.narrowmatcher(subpath, match)
1195 submatch = matchmod.narrowmatcher(subpath, match)
1189 if listsubrepos:
1196 if listsubrepos:
1190 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
1197 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
1191 False))
1198 False))
1192 else:
1199 else:
1193 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
1200 bad.extend(sub.add(ui, submatch, dryrun, listsubrepos, prefix,
1194 True))
1201 True))
1195 except error.LookupError:
1202 except error.LookupError:
1196 ui.status(_("skipping missing subrepository: %s\n")
1203 ui.status(_("skipping missing subrepository: %s\n")
1197 % join(subpath))
1204 % join(subpath))
1198
1205
1199 if not dryrun:
1206 if not dryrun:
1200 rejected = wctx.add(names, prefix)
1207 rejected = wctx.add(names, prefix)
1201 bad.extend(f for f in rejected if f in match.files())
1208 bad.extend(f for f in rejected if f in match.files())
1202 return bad
1209 return bad
1203
1210
1204 def forget(ui, repo, match, prefix, explicitonly):
1211 def forget(ui, repo, match, prefix, explicitonly):
1205 join = lambda f: os.path.join(prefix, f)
1212 join = lambda f: os.path.join(prefix, f)
1206 bad = []
1213 bad = []
1207 oldbad = match.bad
1214 oldbad = match.bad
1208 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1215 match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
1209 wctx = repo[None]
1216 wctx = repo[None]
1210 forgot = []
1217 forgot = []
1211 s = repo.status(match=match, clean=True)
1218 s = repo.status(match=match, clean=True)
1212 forget = sorted(s[0] + s[1] + s[3] + s[6])
1219 forget = sorted(s[0] + s[1] + s[3] + s[6])
1213 if explicitonly:
1220 if explicitonly:
1214 forget = [f for f in forget if match.exact(f)]
1221 forget = [f for f in forget if match.exact(f)]
1215
1222
1216 for subpath in wctx.substate:
1223 for subpath in wctx.substate:
1217 sub = wctx.sub(subpath)
1224 sub = wctx.sub(subpath)
1218 try:
1225 try:
1219 submatch = matchmod.narrowmatcher(subpath, match)
1226 submatch = matchmod.narrowmatcher(subpath, match)
1220 subbad, subforgot = sub.forget(ui, submatch, prefix)
1227 subbad, subforgot = sub.forget(ui, submatch, prefix)
1221 bad.extend([subpath + '/' + f for f in subbad])
1228 bad.extend([subpath + '/' + f for f in subbad])
1222 forgot.extend([subpath + '/' + f for f in subforgot])
1229 forgot.extend([subpath + '/' + f for f in subforgot])
1223 except error.LookupError:
1230 except error.LookupError:
1224 ui.status(_("skipping missing subrepository: %s\n")
1231 ui.status(_("skipping missing subrepository: %s\n")
1225 % join(subpath))
1232 % join(subpath))
1226
1233
1227 if not explicitonly:
1234 if not explicitonly:
1228 for f in match.files():
1235 for f in match.files():
1229 if f not in repo.dirstate and not os.path.isdir(match.rel(join(f))):
1236 if f not in repo.dirstate and not os.path.isdir(match.rel(join(f))):
1230 if f not in forgot:
1237 if f not in forgot:
1231 if os.path.exists(match.rel(join(f))):
1238 if os.path.exists(match.rel(join(f))):
1232 ui.warn(_('not removing %s: '
1239 ui.warn(_('not removing %s: '
1233 'file is already untracked\n')
1240 'file is already untracked\n')
1234 % match.rel(join(f)))
1241 % match.rel(join(f)))
1235 bad.append(f)
1242 bad.append(f)
1236
1243
1237 for f in forget:
1244 for f in forget:
1238 if ui.verbose or not match.exact(f):
1245 if ui.verbose or not match.exact(f):
1239 ui.status(_('removing %s\n') % match.rel(join(f)))
1246 ui.status(_('removing %s\n') % match.rel(join(f)))
1240
1247
1241 rejected = wctx.forget(forget, prefix)
1248 rejected = wctx.forget(forget, prefix)
1242 bad.extend(f for f in rejected if f in match.files())
1249 bad.extend(f for f in rejected if f in match.files())
1243 forgot.extend(forget)
1250 forgot.extend(forget)
1244 return bad, forgot
1251 return bad, forgot
1245
1252
1246 def duplicatecopies(repo, rev, p1):
1253 def duplicatecopies(repo, rev, p1):
1247 "Reproduce copies found in the source revision in the dirstate for grafts"
1254 "Reproduce copies found in the source revision in the dirstate for grafts"
1248 for dst, src in copies.pathcopies(repo[p1], repo[rev]).iteritems():
1255 for dst, src in copies.pathcopies(repo[p1], repo[rev]).iteritems():
1249 repo.dirstate.copy(src, dst)
1256 repo.dirstate.copy(src, dst)
1250
1257
1251 def commit(ui, repo, commitfunc, pats, opts):
1258 def commit(ui, repo, commitfunc, pats, opts):
1252 '''commit the specified files or all outstanding changes'''
1259 '''commit the specified files or all outstanding changes'''
1253 date = opts.get('date')
1260 date = opts.get('date')
1254 if date:
1261 if date:
1255 opts['date'] = util.parsedate(date)
1262 opts['date'] = util.parsedate(date)
1256 message = logmessage(ui, opts)
1263 message = logmessage(ui, opts)
1257
1264
1258 # extract addremove carefully -- this function can be called from a command
1265 # extract addremove carefully -- this function can be called from a command
1259 # that doesn't support addremove
1266 # that doesn't support addremove
1260 if opts.get('addremove'):
1267 if opts.get('addremove'):
1261 scmutil.addremove(repo, pats, opts)
1268 scmutil.addremove(repo, pats, opts)
1262
1269
1263 return commitfunc(ui, repo, message,
1270 return commitfunc(ui, repo, message,
1264 scmutil.match(repo[None], pats, opts), opts)
1271 scmutil.match(repo[None], pats, opts), opts)
1265
1272
1266 def commiteditor(repo, ctx, subs):
1273 def commiteditor(repo, ctx, subs):
1267 if ctx.description():
1274 if ctx.description():
1268 return ctx.description()
1275 return ctx.description()
1269 return commitforceeditor(repo, ctx, subs)
1276 return commitforceeditor(repo, ctx, subs)
1270
1277
1271 def commitforceeditor(repo, ctx, subs):
1278 def commitforceeditor(repo, ctx, subs):
1272 edittext = []
1279 edittext = []
1273 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
1280 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
1274 if ctx.description():
1281 if ctx.description():
1275 edittext.append(ctx.description())
1282 edittext.append(ctx.description())
1276 edittext.append("")
1283 edittext.append("")
1277 edittext.append("") # Empty line between message and comments.
1284 edittext.append("") # Empty line between message and comments.
1278 edittext.append(_("HG: Enter commit message."
1285 edittext.append(_("HG: Enter commit message."
1279 " Lines beginning with 'HG:' are removed."))
1286 " Lines beginning with 'HG:' are removed."))
1280 edittext.append(_("HG: Leave message empty to abort commit."))
1287 edittext.append(_("HG: Leave message empty to abort commit."))
1281 edittext.append("HG: --")
1288 edittext.append("HG: --")
1282 edittext.append(_("HG: user: %s") % ctx.user())
1289 edittext.append(_("HG: user: %s") % ctx.user())
1283 if ctx.p2():
1290 if ctx.p2():
1284 edittext.append(_("HG: branch merge"))
1291 edittext.append(_("HG: branch merge"))
1285 if ctx.branch():
1292 if ctx.branch():
1286 edittext.append(_("HG: branch '%s'") % ctx.branch())
1293 edittext.append(_("HG: branch '%s'") % ctx.branch())
1287 edittext.extend([_("HG: subrepo %s") % s for s in subs])
1294 edittext.extend([_("HG: subrepo %s") % s for s in subs])
1288 edittext.extend([_("HG: added %s") % f for f in added])
1295 edittext.extend([_("HG: added %s") % f for f in added])
1289 edittext.extend([_("HG: changed %s") % f for f in modified])
1296 edittext.extend([_("HG: changed %s") % f for f in modified])
1290 edittext.extend([_("HG: removed %s") % f for f in removed])
1297 edittext.extend([_("HG: removed %s") % f for f in removed])
1291 if not added and not modified and not removed:
1298 if not added and not modified and not removed:
1292 edittext.append(_("HG: no files changed"))
1299 edittext.append(_("HG: no files changed"))
1293 edittext.append("")
1300 edittext.append("")
1294 # run editor in the repository root
1301 # run editor in the repository root
1295 olddir = os.getcwd()
1302 olddir = os.getcwd()
1296 os.chdir(repo.root)
1303 os.chdir(repo.root)
1297 text = repo.ui.edit("\n".join(edittext), ctx.user())
1304 text = repo.ui.edit("\n".join(edittext), ctx.user())
1298 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
1305 text = re.sub("(?m)^HG:.*(\n|$)", "", text)
1299 os.chdir(olddir)
1306 os.chdir(olddir)
1300
1307
1301 if not text.strip():
1308 if not text.strip():
1302 raise util.Abort(_("empty commit message"))
1309 raise util.Abort(_("empty commit message"))
1303
1310
1304 return text
1311 return text
1305
1312
1306 def command(table):
1313 def command(table):
1307 '''returns a function object bound to table which can be used as
1314 '''returns a function object bound to table which can be used as
1308 a decorator for populating table as a command table'''
1315 a decorator for populating table as a command table'''
1309
1316
1310 def cmd(name, options, synopsis=None):
1317 def cmd(name, options, synopsis=None):
1311 def decorator(func):
1318 def decorator(func):
1312 if synopsis:
1319 if synopsis:
1313 table[name] = func, options[:], synopsis
1320 table[name] = func, options[:], synopsis
1314 else:
1321 else:
1315 table[name] = func, options[:]
1322 table[name] = func, options[:]
1316 return func
1323 return func
1317 return decorator
1324 return decorator
1318
1325
1319 return cmd
1326 return cmd
@@ -1,173 +1,174 b''
1
1
2 $ cat >> $HGRCPATH <<EOF
2 $ cat >> $HGRCPATH <<EOF
3 > [extensions]
3 > [extensions]
4 > graphlog =
4 > graphlog =
5 > convert =
5 > convert =
6 > [convert]
6 > [convert]
7 > hg.saverev = yes
7 > hg.saverev = yes
8 > EOF
8 > EOF
9
9
10 $ glog()
10 $ glog()
11 > {
11 > {
12 > hg -R "$1" glog --template '{rev} "{desc}" files: {files}\n'
12 > hg -R "$1" glog --template '{rev} "{desc}" files: {files}\n'
13 > }
13 > }
14
14
15 $ hg init source
15 $ hg init source
16 $ cd source
16 $ cd source
17
17
18 $ echo a > a
18 $ echo a > a
19 $ echo b > b
19 $ echo b > b
20 $ hg ci -d '0 0' -qAm '0: add a b'
20 $ hg ci -d '0 0' -qAm '0: add a b'
21 $ echo c > c
21 $ echo c > c
22 $ hg ci -d '1 0' -qAm '1: add c'
22 $ hg ci -d '1 0' -qAm '1: add c'
23 $ hg copy a e
23 $ hg copy a e
24 $ echo b >> b
24 $ echo b >> b
25 $ hg ci -d '2 0' -qAm '2: copy e from a, change b'
25 $ hg ci -d '2 0' -qAm '2: copy e from a, change b'
26 $ hg up -C 0
26 $ hg up -C 0
27 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
27 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
28 $ echo a >> a
28 $ echo a >> a
29 $ hg ci -d '3 0' -qAm '3: change a'
29 $ hg ci -d '3 0' -qAm '3: change a'
30 $ hg merge
30 $ hg merge
31 merging a and e to e
31 merging a and e to e
32 2 files updated, 1 files merged, 0 files removed, 0 files unresolved
32 2 files updated, 1 files merged, 0 files removed, 0 files unresolved
33 (branch merge, don't forget to commit)
33 (branch merge, don't forget to commit)
34 $ hg copy b d
34 $ hg copy b d
35 $ hg ci -d '4 0' -qAm '4: merge 2 and 3, copy d from b'
35 $ hg ci -d '4 0' -qAm '4: merge 2 and 3, copy d from b'
36 $ echo a >> a
36 $ echo a >> a
37 $ hg ci -d '5 0' -qAm '5: change a'
37 $ hg ci -d '5 0' -qAm '5: change a'
38 $ cd ..
38 $ cd ..
39
39
40 Convert from null revision
40 Convert from null revision
41
41
42 $ hg convert --config convert.hg.startrev=null source full
42 $ hg convert --config convert.hg.startrev=null source full
43 initializing destination full repository
43 initializing destination full repository
44 scanning source...
44 scanning source...
45 sorting...
45 sorting...
46 converting...
46 converting...
47 5 0: add a b
47 5 0: add a b
48 4 1: add c
48 4 1: add c
49 3 2: copy e from a, change b
49 3 2: copy e from a, change b
50 2 3: change a
50 2 3: change a
51 1 4: merge 2 and 3, copy d from b
51 1 4: merge 2 and 3, copy d from b
52 0 5: change a
52 0 5: change a
53
53
54 $ glog full
54 $ glog full
55 o 5 "5: change a" files: a
55 o 5 "5: change a" files: a
56 |
56 |
57 o 4 "4: merge 2 and 3, copy d from b" files: d e
57 o 4 "4: merge 2 and 3, copy d from b" files: d e
58 |\
58 |\
59 | o 3 "3: change a" files: a
59 | o 3 "3: change a" files: a
60 | |
60 | |
61 o | 2 "2: copy e from a, change b" files: b e
61 o | 2 "2: copy e from a, change b" files: b e
62 | |
62 | |
63 o | 1 "1: add c" files: c
63 o | 1 "1: add c" files: c
64 |/
64 |/
65 o 0 "0: add a b" files: a b
65 o 0 "0: add a b" files: a b
66
66
67 $ rm -Rf full
67 $ rm -Rf full
68
68
69 Convert from zero revision
69 Convert from zero revision
70
70
71 $ hg convert --config convert.hg.startrev=0 source full
71 $ hg convert --config convert.hg.startrev=0 source full
72 initializing destination full repository
72 initializing destination full repository
73 scanning source...
73 scanning source...
74 sorting...
74 sorting...
75 converting...
75 converting...
76 5 0: add a b
76 5 0: add a b
77 4 1: add c
77 4 1: add c
78 3 2: copy e from a, change b
78 3 2: copy e from a, change b
79 2 3: change a
79 2 3: change a
80 1 4: merge 2 and 3, copy d from b
80 1 4: merge 2 and 3, copy d from b
81 0 5: change a
81 0 5: change a
82
82
83 $ glog full
83 $ glog full
84 o 5 "5: change a" files: a
84 o 5 "5: change a" files: a
85 |
85 |
86 o 4 "4: merge 2 and 3, copy d from b" files: d e
86 o 4 "4: merge 2 and 3, copy d from b" files: d e
87 |\
87 |\
88 | o 3 "3: change a" files: a
88 | o 3 "3: change a" files: a
89 | |
89 | |
90 o | 2 "2: copy e from a, change b" files: b e
90 o | 2 "2: copy e from a, change b" files: b e
91 | |
91 | |
92 o | 1 "1: add c" files: c
92 o | 1 "1: add c" files: c
93 |/
93 |/
94 o 0 "0: add a b" files: a b
94 o 0 "0: add a b" files: a b
95
95
96 Convert from merge parent
96 Convert from merge parent
97
97
98 $ hg convert --config convert.hg.startrev=1 source conv1
98 $ hg convert --config convert.hg.startrev=1 source conv1
99 initializing destination conv1 repository
99 initializing destination conv1 repository
100 scanning source...
100 scanning source...
101 sorting...
101 sorting...
102 converting...
102 converting...
103 3 1: add c
103 3 1: add c
104 2 2: copy e from a, change b
104 2 2: copy e from a, change b
105 1 4: merge 2 and 3, copy d from b
105 1 4: merge 2 and 3, copy d from b
106 0 5: change a
106 0 5: change a
107
107
108 $ glog conv1
108 $ glog conv1
109 o 3 "5: change a" files: a
109 o 3 "5: change a" files: a
110 |
110 |
111 o 2 "4: merge 2 and 3, copy d from b" files: a d e
111 o 2 "4: merge 2 and 3, copy d from b" files: a d e
112 |
112 |
113 o 1 "2: copy e from a, change b" files: b e
113 o 1 "2: copy e from a, change b" files: b e
114 |
114 |
115 o 0 "1: add c" files: a b c
115 o 0 "1: add c" files: a b c
116
116
117 $ cd conv1
117 $ cd conv1
118 $ hg up -q
118
119
119 Check copy preservation
120 Check copy preservation
120
121
121 $ hg log --follow --copies e
122 $ hg log --follow --copies e
122 changeset: 2:79818a521a40
123 changeset: 2:79818a521a40
123 user: test
124 user: test
124 date: Thu Jan 01 00:00:04 1970 +0000
125 date: Thu Jan 01 00:00:04 1970 +0000
125 summary: 4: merge 2 and 3, copy d from b
126 summary: 4: merge 2 and 3, copy d from b
126
127
127 changeset: 1:3e6201832cce
128 changeset: 1:3e6201832cce
128 user: test
129 user: test
129 date: Thu Jan 01 00:00:02 1970 +0000
130 date: Thu Jan 01 00:00:02 1970 +0000
130 summary: 2: copy e from a, change b
131 summary: 2: copy e from a, change b
131
132
132 Check copy removal on missing parent
133 Check copy removal on missing parent
133
134
134 $ hg log --follow --copies d
135 $ hg log --follow --copies d
135 changeset: 2:79818a521a40
136 changeset: 2:79818a521a40
136 user: test
137 user: test
137 date: Thu Jan 01 00:00:04 1970 +0000
138 date: Thu Jan 01 00:00:04 1970 +0000
138 summary: 4: merge 2 and 3, copy d from b
139 summary: 4: merge 2 and 3, copy d from b
139
140
140 $ hg cat -r tip a b
141 $ hg cat -r tip a b
141 a
142 a
142 a
143 a
143 a
144 a
144 b
145 b
145 b
146 b
146 $ hg -q verify
147 $ hg -q verify
147 $ cd ..
148 $ cd ..
148
149
149 Convert from merge
150 Convert from merge
150
151
151 $ hg convert --config convert.hg.startrev=4 source conv4
152 $ hg convert --config convert.hg.startrev=4 source conv4
152 initializing destination conv4 repository
153 initializing destination conv4 repository
153 scanning source...
154 scanning source...
154 sorting...
155 sorting...
155 converting...
156 converting...
156 1 4: merge 2 and 3, copy d from b
157 1 4: merge 2 and 3, copy d from b
157 0 5: change a
158 0 5: change a
158 $ glog conv4
159 $ glog conv4
159 o 1 "5: change a" files: a
160 o 1 "5: change a" files: a
160 |
161 |
161 o 0 "4: merge 2 and 3, copy d from b" files: a b c d e
162 o 0 "4: merge 2 and 3, copy d from b" files: a b c d e
162
163
163 $ cd conv4
164 $ cd conv4
164 $ hg up -C
165 $ hg up -C
165 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
166 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
166 $ hg cat -r tip a b
167 $ hg cat -r tip a b
167 a
168 a
168 a
169 a
169 a
170 a
170 b
171 b
171 b
172 b
172 $ hg -q verify
173 $ hg -q verify
173 $ cd ..
174 $ cd ..
@@ -1,1222 +1,1239 b''
1 $ "$TESTDIR/hghave" execbit || exit 80
1 $ "$TESTDIR/hghave" execbit || exit 80
2
2
3 The g is crafted to have 2 filelog topological heads in a linear
3 The g is crafted to have 2 filelog topological heads in a linear
4 changeset graph
4 changeset graph
5
5
6 $ hg init a
6 $ hg init a
7 $ cd a
7 $ cd a
8 $ echo a > a
8 $ echo a > a
9 $ echo f > f
9 $ echo f > f
10 $ hg ci -Ama -d '1 0'
10 $ hg ci -Ama -d '1 0'
11 adding a
11 adding a
12 adding f
12 adding f
13
13
14 $ hg cp a b
14 $ hg cp a b
15 $ hg cp f g
15 $ hg cp f g
16 $ hg ci -mb -d '2 0'
16 $ hg ci -mb -d '2 0'
17
17
18 $ mkdir dir
18 $ mkdir dir
19 $ hg mv b dir
19 $ hg mv b dir
20 $ echo g >> g
20 $ echo g >> g
21 $ echo f >> f
21 $ echo f >> f
22 $ hg ci -mc -d '3 0'
22 $ hg ci -mc -d '3 0'
23
23
24 $ hg mv a b
24 $ hg mv a b
25 $ hg cp -f f g
25 $ hg cp -f f g
26 $ echo a > d
26 $ echo a > d
27 $ hg add d
27 $ hg add d
28 $ hg ci -md -d '4 0'
28 $ hg ci -md -d '4 0'
29
29
30 $ hg mv dir/b e
30 $ hg mv dir/b e
31 $ hg ci -me -d '5 0'
31 $ hg ci -me -d '5 0'
32
32
33 $ hg log a
33 $ hg log a
34 changeset: 0:9161b9aeaf16
34 changeset: 0:9161b9aeaf16
35 user: test
35 user: test
36 date: Thu Jan 01 00:00:01 1970 +0000
36 date: Thu Jan 01 00:00:01 1970 +0000
37 summary: a
37 summary: a
38
38
39
39
40 -f, directory
40 -f, directory
41
41
42 $ hg log -f dir
42 $ hg log -f dir
43 abort: cannot follow nonexistent file: "dir"
43 abort: cannot follow file not in parent revision: "dir"
44 [255]
44 [255]
45
45
46 -f, but no args
46 -f, but no args
47
47
48 $ hg log -f
48 $ hg log -f
49 changeset: 4:7e4639b4691b
49 changeset: 4:7e4639b4691b
50 tag: tip
50 tag: tip
51 user: test
51 user: test
52 date: Thu Jan 01 00:00:05 1970 +0000
52 date: Thu Jan 01 00:00:05 1970 +0000
53 summary: e
53 summary: e
54
54
55 changeset: 3:2ca5ba701980
55 changeset: 3:2ca5ba701980
56 user: test
56 user: test
57 date: Thu Jan 01 00:00:04 1970 +0000
57 date: Thu Jan 01 00:00:04 1970 +0000
58 summary: d
58 summary: d
59
59
60 changeset: 2:f8954cd4dc1f
60 changeset: 2:f8954cd4dc1f
61 user: test
61 user: test
62 date: Thu Jan 01 00:00:03 1970 +0000
62 date: Thu Jan 01 00:00:03 1970 +0000
63 summary: c
63 summary: c
64
64
65 changeset: 1:d89b0a12d229
65 changeset: 1:d89b0a12d229
66 user: test
66 user: test
67 date: Thu Jan 01 00:00:02 1970 +0000
67 date: Thu Jan 01 00:00:02 1970 +0000
68 summary: b
68 summary: b
69
69
70 changeset: 0:9161b9aeaf16
70 changeset: 0:9161b9aeaf16
71 user: test
71 user: test
72 date: Thu Jan 01 00:00:01 1970 +0000
72 date: Thu Jan 01 00:00:01 1970 +0000
73 summary: a
73 summary: a
74
74
75
75
76 one rename
76 one rename
77
77
78 $ hg up -q 2
78 $ hg log -vf a
79 $ hg log -vf a
79 changeset: 0:9161b9aeaf16
80 changeset: 0:9161b9aeaf16
80 user: test
81 user: test
81 date: Thu Jan 01 00:00:01 1970 +0000
82 date: Thu Jan 01 00:00:01 1970 +0000
82 files: a f
83 files: a f
83 description:
84 description:
84 a
85 a
85
86
86
87
87
88
88 many renames
89 many renames
89
90
91 $ hg up -q tip
90 $ hg log -vf e
92 $ hg log -vf e
91 changeset: 4:7e4639b4691b
93 changeset: 4:7e4639b4691b
92 tag: tip
94 tag: tip
93 user: test
95 user: test
94 date: Thu Jan 01 00:00:05 1970 +0000
96 date: Thu Jan 01 00:00:05 1970 +0000
95 files: dir/b e
97 files: dir/b e
96 description:
98 description:
97 e
99 e
98
100
99
101
100 changeset: 2:f8954cd4dc1f
102 changeset: 2:f8954cd4dc1f
101 user: test
103 user: test
102 date: Thu Jan 01 00:00:03 1970 +0000
104 date: Thu Jan 01 00:00:03 1970 +0000
103 files: b dir/b f g
105 files: b dir/b f g
104 description:
106 description:
105 c
107 c
106
108
107
109
108 changeset: 1:d89b0a12d229
110 changeset: 1:d89b0a12d229
109 user: test
111 user: test
110 date: Thu Jan 01 00:00:02 1970 +0000
112 date: Thu Jan 01 00:00:02 1970 +0000
111 files: b g
113 files: b g
112 description:
114 description:
113 b
115 b
114
116
115
117
116 changeset: 0:9161b9aeaf16
118 changeset: 0:9161b9aeaf16
117 user: test
119 user: test
118 date: Thu Jan 01 00:00:01 1970 +0000
120 date: Thu Jan 01 00:00:01 1970 +0000
119 files: a f
121 files: a f
120 description:
122 description:
121 a
123 a
122
124
123
125
124
126
125
127
126 log -pf dir/b
128 log -pf dir/b
127
129
130 $ hg up -q 3
128 $ hg log -pf dir/b
131 $ hg log -pf dir/b
129 changeset: 2:f8954cd4dc1f
132 changeset: 2:f8954cd4dc1f
130 user: test
133 user: test
131 date: Thu Jan 01 00:00:03 1970 +0000
134 date: Thu Jan 01 00:00:03 1970 +0000
132 summary: c
135 summary: c
133
136
134 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
137 diff -r d89b0a12d229 -r f8954cd4dc1f dir/b
135 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
138 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
136 +++ b/dir/b Thu Jan 01 00:00:03 1970 +0000
139 +++ b/dir/b Thu Jan 01 00:00:03 1970 +0000
137 @@ -0,0 +1,1 @@
140 @@ -0,0 +1,1 @@
138 +a
141 +a
139
142
140 changeset: 1:d89b0a12d229
143 changeset: 1:d89b0a12d229
141 user: test
144 user: test
142 date: Thu Jan 01 00:00:02 1970 +0000
145 date: Thu Jan 01 00:00:02 1970 +0000
143 summary: b
146 summary: b
144
147
145 diff -r 9161b9aeaf16 -r d89b0a12d229 b
148 diff -r 9161b9aeaf16 -r d89b0a12d229 b
146 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
149 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
147 +++ b/b Thu Jan 01 00:00:02 1970 +0000
150 +++ b/b Thu Jan 01 00:00:02 1970 +0000
148 @@ -0,0 +1,1 @@
151 @@ -0,0 +1,1 @@
149 +a
152 +a
150
153
151 changeset: 0:9161b9aeaf16
154 changeset: 0:9161b9aeaf16
152 user: test
155 user: test
153 date: Thu Jan 01 00:00:01 1970 +0000
156 date: Thu Jan 01 00:00:01 1970 +0000
154 summary: a
157 summary: a
155
158
156 diff -r 000000000000 -r 9161b9aeaf16 a
159 diff -r 000000000000 -r 9161b9aeaf16 a
157 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
160 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
158 +++ b/a Thu Jan 01 00:00:01 1970 +0000
161 +++ b/a Thu Jan 01 00:00:01 1970 +0000
159 @@ -0,0 +1,1 @@
162 @@ -0,0 +1,1 @@
160 +a
163 +a
161
164
162
165
163 log -vf dir/b
166 log -vf dir/b
164
167
165 $ hg log -vf dir/b
168 $ hg log -vf dir/b
166 changeset: 2:f8954cd4dc1f
169 changeset: 2:f8954cd4dc1f
167 user: test
170 user: test
168 date: Thu Jan 01 00:00:03 1970 +0000
171 date: Thu Jan 01 00:00:03 1970 +0000
169 files: b dir/b f g
172 files: b dir/b f g
170 description:
173 description:
171 c
174 c
172
175
173
176
174 changeset: 1:d89b0a12d229
177 changeset: 1:d89b0a12d229
175 user: test
178 user: test
176 date: Thu Jan 01 00:00:02 1970 +0000
179 date: Thu Jan 01 00:00:02 1970 +0000
177 files: b g
180 files: b g
178 description:
181 description:
179 b
182 b
180
183
181
184
182 changeset: 0:9161b9aeaf16
185 changeset: 0:9161b9aeaf16
183 user: test
186 user: test
184 date: Thu Jan 01 00:00:01 1970 +0000
187 date: Thu Jan 01 00:00:01 1970 +0000
185 files: a f
188 files: a f
186 description:
189 description:
187 a
190 a
188
191
189
192
190
193
191
194
195 -f and multiple filelog heads
196
197 $ hg up -q 2
198 $ hg log -f g --template '{rev}\n'
199 2
200 1
201 0
202 $ hg up -q tip
203 $ hg log -f g --template '{rev}\n'
204 3
205 2
206 0
207
208
192 log copies with --copies
209 log copies with --copies
193
210
194 $ hg log -vC --template '{rev} {file_copies}\n'
211 $ hg log -vC --template '{rev} {file_copies}\n'
195 4 e (dir/b)
212 4 e (dir/b)
196 3 b (a)g (f)
213 3 b (a)g (f)
197 2 dir/b (b)
214 2 dir/b (b)
198 1 b (a)g (f)
215 1 b (a)g (f)
199 0
216 0
200
217
201 log copies switch without --copies, with old filecopy template
218 log copies switch without --copies, with old filecopy template
202
219
203 $ hg log -v --template '{rev} {file_copies_switch%filecopy}\n'
220 $ hg log -v --template '{rev} {file_copies_switch%filecopy}\n'
204 4
221 4
205 3
222 3
206 2
223 2
207 1
224 1
208 0
225 0
209
226
210 log copies switch with --copies
227 log copies switch with --copies
211
228
212 $ hg log -vC --template '{rev} {file_copies_switch}\n'
229 $ hg log -vC --template '{rev} {file_copies_switch}\n'
213 4 e (dir/b)
230 4 e (dir/b)
214 3 b (a)g (f)
231 3 b (a)g (f)
215 2 dir/b (b)
232 2 dir/b (b)
216 1 b (a)g (f)
233 1 b (a)g (f)
217 0
234 0
218
235
219
236
220 log copies with hardcoded style and with --style=default
237 log copies with hardcoded style and with --style=default
221
238
222 $ hg log -vC -r4
239 $ hg log -vC -r4
223 changeset: 4:7e4639b4691b
240 changeset: 4:7e4639b4691b
224 tag: tip
241 tag: tip
225 user: test
242 user: test
226 date: Thu Jan 01 00:00:05 1970 +0000
243 date: Thu Jan 01 00:00:05 1970 +0000
227 files: dir/b e
244 files: dir/b e
228 copies: e (dir/b)
245 copies: e (dir/b)
229 description:
246 description:
230 e
247 e
231
248
232
249
233 $ hg log -vC -r4 --style=default
250 $ hg log -vC -r4 --style=default
234 changeset: 4:7e4639b4691b
251 changeset: 4:7e4639b4691b
235 tag: tip
252 tag: tip
236 user: test
253 user: test
237 date: Thu Jan 01 00:00:05 1970 +0000
254 date: Thu Jan 01 00:00:05 1970 +0000
238 files: dir/b e
255 files: dir/b e
239 copies: e (dir/b)
256 copies: e (dir/b)
240 description:
257 description:
241 e
258 e
242
259
243
260
244
261
245
262
246 log copies, non-linear manifest
263 log copies, non-linear manifest
247
264
248 $ hg up -C 3
265 $ hg up -C 3
249 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
266 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
250 $ hg mv dir/b e
267 $ hg mv dir/b e
251 $ echo foo > foo
268 $ echo foo > foo
252 $ hg ci -Ame2 -d '6 0'
269 $ hg ci -Ame2 -d '6 0'
253 adding foo
270 adding foo
254 created new head
271 created new head
255 $ hg log -v --template '{rev} {file_copies}\n' -r 5
272 $ hg log -v --template '{rev} {file_copies}\n' -r 5
256 5 e (dir/b)
273 5 e (dir/b)
257
274
258
275
259 log copies, execute bit set
276 log copies, execute bit set
260
277
261 $ chmod +x e
278 $ chmod +x e
262 $ hg ci -me3 -d '7 0'
279 $ hg ci -me3 -d '7 0'
263 $ hg log -v --template '{rev} {file_copies}\n' -r 6
280 $ hg log -v --template '{rev} {file_copies}\n' -r 6
264 6
281 6
265
282
266
283
267 log -p d
284 log -p d
268
285
269 $ hg log -pv d
286 $ hg log -pv d
270 changeset: 3:2ca5ba701980
287 changeset: 3:2ca5ba701980
271 user: test
288 user: test
272 date: Thu Jan 01 00:00:04 1970 +0000
289 date: Thu Jan 01 00:00:04 1970 +0000
273 files: a b d g
290 files: a b d g
274 description:
291 description:
275 d
292 d
276
293
277
294
278 diff -r f8954cd4dc1f -r 2ca5ba701980 d
295 diff -r f8954cd4dc1f -r 2ca5ba701980 d
279 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
296 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
280 +++ b/d Thu Jan 01 00:00:04 1970 +0000
297 +++ b/d Thu Jan 01 00:00:04 1970 +0000
281 @@ -0,0 +1,1 @@
298 @@ -0,0 +1,1 @@
282 +a
299 +a
283
300
284
301
285
302
286 log --removed file
303 log --removed file
287
304
288 $ hg log --removed -v a
305 $ hg log --removed -v a
289 changeset: 3:2ca5ba701980
306 changeset: 3:2ca5ba701980
290 user: test
307 user: test
291 date: Thu Jan 01 00:00:04 1970 +0000
308 date: Thu Jan 01 00:00:04 1970 +0000
292 files: a b d g
309 files: a b d g
293 description:
310 description:
294 d
311 d
295
312
296
313
297 changeset: 0:9161b9aeaf16
314 changeset: 0:9161b9aeaf16
298 user: test
315 user: test
299 date: Thu Jan 01 00:00:01 1970 +0000
316 date: Thu Jan 01 00:00:01 1970 +0000
300 files: a f
317 files: a f
301 description:
318 description:
302 a
319 a
303
320
304
321
305
322
306 log --removed revrange file
323 log --removed revrange file
307
324
308 $ hg log --removed -v -r0:2 a
325 $ hg log --removed -v -r0:2 a
309 changeset: 0:9161b9aeaf16
326 changeset: 0:9161b9aeaf16
310 user: test
327 user: test
311 date: Thu Jan 01 00:00:01 1970 +0000
328 date: Thu Jan 01 00:00:01 1970 +0000
312 files: a f
329 files: a f
313 description:
330 description:
314 a
331 a
315
332
316
333
317
334
318
335
319 log --follow tests
336 log --follow tests
320
337
321 $ hg init ../follow
338 $ hg init ../follow
322 $ cd ../follow
339 $ cd ../follow
323
340
324 $ echo base > base
341 $ echo base > base
325 $ hg ci -Ambase -d '1 0'
342 $ hg ci -Ambase -d '1 0'
326 adding base
343 adding base
327
344
328 $ echo r1 >> base
345 $ echo r1 >> base
329 $ hg ci -Amr1 -d '1 0'
346 $ hg ci -Amr1 -d '1 0'
330 $ echo r2 >> base
347 $ echo r2 >> base
331 $ hg ci -Amr2 -d '1 0'
348 $ hg ci -Amr2 -d '1 0'
332
349
333 $ hg up -C 1
350 $ hg up -C 1
334 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
351 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
335 $ echo b1 > b1
352 $ echo b1 > b1
336 $ hg ci -Amb1 -d '1 0'
353 $ hg ci -Amb1 -d '1 0'
337 adding b1
354 adding b1
338 created new head
355 created new head
339
356
340
357
341 log -f
358 log -f
342
359
343 $ hg log -f
360 $ hg log -f
344 changeset: 3:e62f78d544b4
361 changeset: 3:e62f78d544b4
345 tag: tip
362 tag: tip
346 parent: 1:3d5bf5654eda
363 parent: 1:3d5bf5654eda
347 user: test
364 user: test
348 date: Thu Jan 01 00:00:01 1970 +0000
365 date: Thu Jan 01 00:00:01 1970 +0000
349 summary: b1
366 summary: b1
350
367
351 changeset: 1:3d5bf5654eda
368 changeset: 1:3d5bf5654eda
352 user: test
369 user: test
353 date: Thu Jan 01 00:00:01 1970 +0000
370 date: Thu Jan 01 00:00:01 1970 +0000
354 summary: r1
371 summary: r1
355
372
356 changeset: 0:67e992f2c4f3
373 changeset: 0:67e992f2c4f3
357 user: test
374 user: test
358 date: Thu Jan 01 00:00:01 1970 +0000
375 date: Thu Jan 01 00:00:01 1970 +0000
359 summary: base
376 summary: base
360
377
361
378
362
379
363 log -f -r 1:tip
380 log -f -r 1:tip
364
381
365 $ hg up -C 0
382 $ hg up -C 0
366 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
383 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
367 $ echo b2 > b2
384 $ echo b2 > b2
368 $ hg ci -Amb2 -d '1 0'
385 $ hg ci -Amb2 -d '1 0'
369 adding b2
386 adding b2
370 created new head
387 created new head
371 $ hg log -f -r 1:tip
388 $ hg log -f -r 1:tip
372 changeset: 1:3d5bf5654eda
389 changeset: 1:3d5bf5654eda
373 user: test
390 user: test
374 date: Thu Jan 01 00:00:01 1970 +0000
391 date: Thu Jan 01 00:00:01 1970 +0000
375 summary: r1
392 summary: r1
376
393
377 changeset: 2:60c670bf5b30
394 changeset: 2:60c670bf5b30
378 user: test
395 user: test
379 date: Thu Jan 01 00:00:01 1970 +0000
396 date: Thu Jan 01 00:00:01 1970 +0000
380 summary: r2
397 summary: r2
381
398
382 changeset: 3:e62f78d544b4
399 changeset: 3:e62f78d544b4
383 parent: 1:3d5bf5654eda
400 parent: 1:3d5bf5654eda
384 user: test
401 user: test
385 date: Thu Jan 01 00:00:01 1970 +0000
402 date: Thu Jan 01 00:00:01 1970 +0000
386 summary: b1
403 summary: b1
387
404
388
405
389
406
390 log -r . with two parents
407 log -r . with two parents
391
408
392 $ hg up -C 3
409 $ hg up -C 3
393 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
410 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
394 $ hg merge tip
411 $ hg merge tip
395 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
412 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
396 (branch merge, don't forget to commit)
413 (branch merge, don't forget to commit)
397 $ hg log -r .
414 $ hg log -r .
398 changeset: 3:e62f78d544b4
415 changeset: 3:e62f78d544b4
399 parent: 1:3d5bf5654eda
416 parent: 1:3d5bf5654eda
400 user: test
417 user: test
401 date: Thu Jan 01 00:00:01 1970 +0000
418 date: Thu Jan 01 00:00:01 1970 +0000
402 summary: b1
419 summary: b1
403
420
404
421
405
422
406 log -r . with one parent
423 log -r . with one parent
407
424
408 $ hg ci -mm12 -d '1 0'
425 $ hg ci -mm12 -d '1 0'
409 $ hg log -r .
426 $ hg log -r .
410 changeset: 5:302e9dd6890d
427 changeset: 5:302e9dd6890d
411 tag: tip
428 tag: tip
412 parent: 3:e62f78d544b4
429 parent: 3:e62f78d544b4
413 parent: 4:ddb82e70d1a1
430 parent: 4:ddb82e70d1a1
414 user: test
431 user: test
415 date: Thu Jan 01 00:00:01 1970 +0000
432 date: Thu Jan 01 00:00:01 1970 +0000
416 summary: m12
433 summary: m12
417
434
418
435
419 $ echo postm >> b1
436 $ echo postm >> b1
420 $ hg ci -Amb1.1 -d'1 0'
437 $ hg ci -Amb1.1 -d'1 0'
421
438
422
439
423 log --follow-first
440 log --follow-first
424
441
425 $ hg log --follow-first
442 $ hg log --follow-first
426 changeset: 6:2404bbcab562
443 changeset: 6:2404bbcab562
427 tag: tip
444 tag: tip
428 user: test
445 user: test
429 date: Thu Jan 01 00:00:01 1970 +0000
446 date: Thu Jan 01 00:00:01 1970 +0000
430 summary: b1.1
447 summary: b1.1
431
448
432 changeset: 5:302e9dd6890d
449 changeset: 5:302e9dd6890d
433 parent: 3:e62f78d544b4
450 parent: 3:e62f78d544b4
434 parent: 4:ddb82e70d1a1
451 parent: 4:ddb82e70d1a1
435 user: test
452 user: test
436 date: Thu Jan 01 00:00:01 1970 +0000
453 date: Thu Jan 01 00:00:01 1970 +0000
437 summary: m12
454 summary: m12
438
455
439 changeset: 3:e62f78d544b4
456 changeset: 3:e62f78d544b4
440 parent: 1:3d5bf5654eda
457 parent: 1:3d5bf5654eda
441 user: test
458 user: test
442 date: Thu Jan 01 00:00:01 1970 +0000
459 date: Thu Jan 01 00:00:01 1970 +0000
443 summary: b1
460 summary: b1
444
461
445 changeset: 1:3d5bf5654eda
462 changeset: 1:3d5bf5654eda
446 user: test
463 user: test
447 date: Thu Jan 01 00:00:01 1970 +0000
464 date: Thu Jan 01 00:00:01 1970 +0000
448 summary: r1
465 summary: r1
449
466
450 changeset: 0:67e992f2c4f3
467 changeset: 0:67e992f2c4f3
451 user: test
468 user: test
452 date: Thu Jan 01 00:00:01 1970 +0000
469 date: Thu Jan 01 00:00:01 1970 +0000
453 summary: base
470 summary: base
454
471
455
472
456
473
457 log -P 2
474 log -P 2
458
475
459 $ hg log -P 2
476 $ hg log -P 2
460 changeset: 6:2404bbcab562
477 changeset: 6:2404bbcab562
461 tag: tip
478 tag: tip
462 user: test
479 user: test
463 date: Thu Jan 01 00:00:01 1970 +0000
480 date: Thu Jan 01 00:00:01 1970 +0000
464 summary: b1.1
481 summary: b1.1
465
482
466 changeset: 5:302e9dd6890d
483 changeset: 5:302e9dd6890d
467 parent: 3:e62f78d544b4
484 parent: 3:e62f78d544b4
468 parent: 4:ddb82e70d1a1
485 parent: 4:ddb82e70d1a1
469 user: test
486 user: test
470 date: Thu Jan 01 00:00:01 1970 +0000
487 date: Thu Jan 01 00:00:01 1970 +0000
471 summary: m12
488 summary: m12
472
489
473 changeset: 4:ddb82e70d1a1
490 changeset: 4:ddb82e70d1a1
474 parent: 0:67e992f2c4f3
491 parent: 0:67e992f2c4f3
475 user: test
492 user: test
476 date: Thu Jan 01 00:00:01 1970 +0000
493 date: Thu Jan 01 00:00:01 1970 +0000
477 summary: b2
494 summary: b2
478
495
479 changeset: 3:e62f78d544b4
496 changeset: 3:e62f78d544b4
480 parent: 1:3d5bf5654eda
497 parent: 1:3d5bf5654eda
481 user: test
498 user: test
482 date: Thu Jan 01 00:00:01 1970 +0000
499 date: Thu Jan 01 00:00:01 1970 +0000
483 summary: b1
500 summary: b1
484
501
485
502
486
503
487 log -r tip -p --git
504 log -r tip -p --git
488
505
489 $ hg log -r tip -p --git
506 $ hg log -r tip -p --git
490 changeset: 6:2404bbcab562
507 changeset: 6:2404bbcab562
491 tag: tip
508 tag: tip
492 user: test
509 user: test
493 date: Thu Jan 01 00:00:01 1970 +0000
510 date: Thu Jan 01 00:00:01 1970 +0000
494 summary: b1.1
511 summary: b1.1
495
512
496 diff --git a/b1 b/b1
513 diff --git a/b1 b/b1
497 --- a/b1
514 --- a/b1
498 +++ b/b1
515 +++ b/b1
499 @@ -1,1 +1,2 @@
516 @@ -1,1 +1,2 @@
500 b1
517 b1
501 +postm
518 +postm
502
519
503
520
504
521
505 log -r ""
522 log -r ""
506
523
507 $ hg log -r ''
524 $ hg log -r ''
508 hg: parse error: empty query
525 hg: parse error: empty query
509 [255]
526 [255]
510
527
511 log -r <some unknown node id>
528 log -r <some unknown node id>
512
529
513 $ hg log -r 1000000000000000000000000000000000000000
530 $ hg log -r 1000000000000000000000000000000000000000
514 abort: unknown revision '1000000000000000000000000000000000000000'!
531 abort: unknown revision '1000000000000000000000000000000000000000'!
515 [255]
532 [255]
516
533
517 log -k r1
534 log -k r1
518
535
519 $ hg log -k r1
536 $ hg log -k r1
520 changeset: 1:3d5bf5654eda
537 changeset: 1:3d5bf5654eda
521 user: test
538 user: test
522 date: Thu Jan 01 00:00:01 1970 +0000
539 date: Thu Jan 01 00:00:01 1970 +0000
523 summary: r1
540 summary: r1
524
541
525 log -d " " (whitespaces only)
542 log -d " " (whitespaces only)
526
543
527 $ hg log -d " "
544 $ hg log -d " "
528 abort: dates cannot consist entirely of whitespace
545 abort: dates cannot consist entirely of whitespace
529 [255]
546 [255]
530
547
531 log -d -1
548 log -d -1
532
549
533 $ hg log -d -1
550 $ hg log -d -1
534
551
535 log -d ">"
552 log -d ">"
536
553
537 $ hg log -d ">"
554 $ hg log -d ">"
538 abort: invalid day spec, use '>DATE'
555 abort: invalid day spec, use '>DATE'
539 [255]
556 [255]
540
557
541 log -d "<"
558 log -d "<"
542
559
543 $ hg log -d "<"
560 $ hg log -d "<"
544 abort: invalid day spec, use '<DATE'
561 abort: invalid day spec, use '<DATE'
545 [255]
562 [255]
546
563
547 Negative ranges
564 Negative ranges
548 $ hg log -d "--2"
565 $ hg log -d "--2"
549 abort: -2 must be nonnegative (see 'hg help dates')
566 abort: -2 must be nonnegative (see 'hg help dates')
550 [255]
567 [255]
551
568
552
569
553 log -p -l2 --color=always
570 log -p -l2 --color=always
554
571
555 $ hg --config extensions.color= --config color.mode=ansi \
572 $ hg --config extensions.color= --config color.mode=ansi \
556 > log -p -l2 --color=always
573 > log -p -l2 --color=always
557 \x1b[0;33mchangeset: 6:2404bbcab562\x1b[0m (esc)
574 \x1b[0;33mchangeset: 6:2404bbcab562\x1b[0m (esc)
558 tag: tip
575 tag: tip
559 user: test
576 user: test
560 date: Thu Jan 01 00:00:01 1970 +0000
577 date: Thu Jan 01 00:00:01 1970 +0000
561 summary: b1.1
578 summary: b1.1
562
579
563 \x1b[0;1mdiff -r 302e9dd6890d -r 2404bbcab562 b1\x1b[0m (esc)
580 \x1b[0;1mdiff -r 302e9dd6890d -r 2404bbcab562 b1\x1b[0m (esc)
564 \x1b[0;31;1m--- a/b1 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
581 \x1b[0;31;1m--- a/b1 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
565 \x1b[0;32;1m+++ b/b1 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
582 \x1b[0;32;1m+++ b/b1 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
566 \x1b[0;35m@@ -1,1 +1,2 @@\x1b[0m (esc)
583 \x1b[0;35m@@ -1,1 +1,2 @@\x1b[0m (esc)
567 b1
584 b1
568 \x1b[0;32m+postm\x1b[0m (esc)
585 \x1b[0;32m+postm\x1b[0m (esc)
569
586
570 \x1b[0;33mchangeset: 5:302e9dd6890d\x1b[0m (esc)
587 \x1b[0;33mchangeset: 5:302e9dd6890d\x1b[0m (esc)
571 parent: 3:e62f78d544b4
588 parent: 3:e62f78d544b4
572 parent: 4:ddb82e70d1a1
589 parent: 4:ddb82e70d1a1
573 user: test
590 user: test
574 date: Thu Jan 01 00:00:01 1970 +0000
591 date: Thu Jan 01 00:00:01 1970 +0000
575 summary: m12
592 summary: m12
576
593
577 \x1b[0;1mdiff -r e62f78d544b4 -r 302e9dd6890d b2\x1b[0m (esc)
594 \x1b[0;1mdiff -r e62f78d544b4 -r 302e9dd6890d b2\x1b[0m (esc)
578 \x1b[0;31;1m--- /dev/null Thu Jan 01 00:00:00 1970 +0000\x1b[0m (esc)
595 \x1b[0;31;1m--- /dev/null Thu Jan 01 00:00:00 1970 +0000\x1b[0m (esc)
579 \x1b[0;32;1m+++ b/b2 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
596 \x1b[0;32;1m+++ b/b2 Thu Jan 01 00:00:01 1970 +0000\x1b[0m (esc)
580 \x1b[0;35m@@ -0,0 +1,1 @@\x1b[0m (esc)
597 \x1b[0;35m@@ -0,0 +1,1 @@\x1b[0m (esc)
581 \x1b[0;32m+b2\x1b[0m (esc)
598 \x1b[0;32m+b2\x1b[0m (esc)
582
599
583
600
584
601
585 log -r tip --stat
602 log -r tip --stat
586
603
587 $ hg log -r tip --stat
604 $ hg log -r tip --stat
588 changeset: 6:2404bbcab562
605 changeset: 6:2404bbcab562
589 tag: tip
606 tag: tip
590 user: test
607 user: test
591 date: Thu Jan 01 00:00:01 1970 +0000
608 date: Thu Jan 01 00:00:01 1970 +0000
592 summary: b1.1
609 summary: b1.1
593
610
594 b1 | 1 +
611 b1 | 1 +
595 1 files changed, 1 insertions(+), 0 deletions(-)
612 1 files changed, 1 insertions(+), 0 deletions(-)
596
613
597
614
598 $ cd ..
615 $ cd ..
599
616
600 $ hg init usertest
617 $ hg init usertest
601 $ cd usertest
618 $ cd usertest
602
619
603 $ echo a > a
620 $ echo a > a
604 $ hg ci -A -m "a" -u "User One <user1@example.org>"
621 $ hg ci -A -m "a" -u "User One <user1@example.org>"
605 adding a
622 adding a
606 $ echo b > b
623 $ echo b > b
607 $ hg ci -A -m "b" -u "User Two <user2@example.org>"
624 $ hg ci -A -m "b" -u "User Two <user2@example.org>"
608 adding b
625 adding b
609
626
610 $ hg log -u "User One <user1@example.org>"
627 $ hg log -u "User One <user1@example.org>"
611 changeset: 0:29a4c94f1924
628 changeset: 0:29a4c94f1924
612 user: User One <user1@example.org>
629 user: User One <user1@example.org>
613 date: Thu Jan 01 00:00:00 1970 +0000
630 date: Thu Jan 01 00:00:00 1970 +0000
614 summary: a
631 summary: a
615
632
616 $ hg log -u "user1" -u "user2"
633 $ hg log -u "user1" -u "user2"
617 changeset: 1:e834b5e69c0e
634 changeset: 1:e834b5e69c0e
618 tag: tip
635 tag: tip
619 user: User Two <user2@example.org>
636 user: User Two <user2@example.org>
620 date: Thu Jan 01 00:00:00 1970 +0000
637 date: Thu Jan 01 00:00:00 1970 +0000
621 summary: b
638 summary: b
622
639
623 changeset: 0:29a4c94f1924
640 changeset: 0:29a4c94f1924
624 user: User One <user1@example.org>
641 user: User One <user1@example.org>
625 date: Thu Jan 01 00:00:00 1970 +0000
642 date: Thu Jan 01 00:00:00 1970 +0000
626 summary: a
643 summary: a
627
644
628 $ hg log -u "user3"
645 $ hg log -u "user3"
629
646
630 $ cd ..
647 $ cd ..
631
648
632 $ hg init branches
649 $ hg init branches
633 $ cd branches
650 $ cd branches
634
651
635 $ echo a > a
652 $ echo a > a
636 $ hg ci -A -m "commit on default"
653 $ hg ci -A -m "commit on default"
637 adding a
654 adding a
638 $ hg branch test
655 $ hg branch test
639 marked working directory as branch test
656 marked working directory as branch test
640 (branches are permanent and global, did you want a bookmark?)
657 (branches are permanent and global, did you want a bookmark?)
641 $ echo b > b
658 $ echo b > b
642 $ hg ci -A -m "commit on test"
659 $ hg ci -A -m "commit on test"
643 adding b
660 adding b
644
661
645 $ hg up default
662 $ hg up default
646 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
663 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
647 $ echo c > c
664 $ echo c > c
648 $ hg ci -A -m "commit on default"
665 $ hg ci -A -m "commit on default"
649 adding c
666 adding c
650 $ hg up test
667 $ hg up test
651 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
668 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
652 $ echo c > c
669 $ echo c > c
653 $ hg ci -A -m "commit on test"
670 $ hg ci -A -m "commit on test"
654 adding c
671 adding c
655
672
656
673
657 log -b default
674 log -b default
658
675
659 $ hg log -b default
676 $ hg log -b default
660 changeset: 2:c3a4f03cc9a7
677 changeset: 2:c3a4f03cc9a7
661 parent: 0:24427303d56f
678 parent: 0:24427303d56f
662 user: test
679 user: test
663 date: Thu Jan 01 00:00:00 1970 +0000
680 date: Thu Jan 01 00:00:00 1970 +0000
664 summary: commit on default
681 summary: commit on default
665
682
666 changeset: 0:24427303d56f
683 changeset: 0:24427303d56f
667 user: test
684 user: test
668 date: Thu Jan 01 00:00:00 1970 +0000
685 date: Thu Jan 01 00:00:00 1970 +0000
669 summary: commit on default
686 summary: commit on default
670
687
671
688
672
689
673 log -b test
690 log -b test
674
691
675 $ hg log -b test
692 $ hg log -b test
676 changeset: 3:f5d8de11c2e2
693 changeset: 3:f5d8de11c2e2
677 branch: test
694 branch: test
678 tag: tip
695 tag: tip
679 parent: 1:d32277701ccb
696 parent: 1:d32277701ccb
680 user: test
697 user: test
681 date: Thu Jan 01 00:00:00 1970 +0000
698 date: Thu Jan 01 00:00:00 1970 +0000
682 summary: commit on test
699 summary: commit on test
683
700
684 changeset: 1:d32277701ccb
701 changeset: 1:d32277701ccb
685 branch: test
702 branch: test
686 user: test
703 user: test
687 date: Thu Jan 01 00:00:00 1970 +0000
704 date: Thu Jan 01 00:00:00 1970 +0000
688 summary: commit on test
705 summary: commit on test
689
706
690
707
691
708
692 log -b dummy
709 log -b dummy
693
710
694 $ hg log -b dummy
711 $ hg log -b dummy
695 abort: unknown revision 'dummy'!
712 abort: unknown revision 'dummy'!
696 [255]
713 [255]
697
714
698
715
699 log -b .
716 log -b .
700
717
701 $ hg log -b .
718 $ hg log -b .
702 changeset: 3:f5d8de11c2e2
719 changeset: 3:f5d8de11c2e2
703 branch: test
720 branch: test
704 tag: tip
721 tag: tip
705 parent: 1:d32277701ccb
722 parent: 1:d32277701ccb
706 user: test
723 user: test
707 date: Thu Jan 01 00:00:00 1970 +0000
724 date: Thu Jan 01 00:00:00 1970 +0000
708 summary: commit on test
725 summary: commit on test
709
726
710 changeset: 1:d32277701ccb
727 changeset: 1:d32277701ccb
711 branch: test
728 branch: test
712 user: test
729 user: test
713 date: Thu Jan 01 00:00:00 1970 +0000
730 date: Thu Jan 01 00:00:00 1970 +0000
714 summary: commit on test
731 summary: commit on test
715
732
716
733
717
734
718 log -b default -b test
735 log -b default -b test
719
736
720 $ hg log -b default -b test
737 $ hg log -b default -b test
721 changeset: 3:f5d8de11c2e2
738 changeset: 3:f5d8de11c2e2
722 branch: test
739 branch: test
723 tag: tip
740 tag: tip
724 parent: 1:d32277701ccb
741 parent: 1:d32277701ccb
725 user: test
742 user: test
726 date: Thu Jan 01 00:00:00 1970 +0000
743 date: Thu Jan 01 00:00:00 1970 +0000
727 summary: commit on test
744 summary: commit on test
728
745
729 changeset: 2:c3a4f03cc9a7
746 changeset: 2:c3a4f03cc9a7
730 parent: 0:24427303d56f
747 parent: 0:24427303d56f
731 user: test
748 user: test
732 date: Thu Jan 01 00:00:00 1970 +0000
749 date: Thu Jan 01 00:00:00 1970 +0000
733 summary: commit on default
750 summary: commit on default
734
751
735 changeset: 1:d32277701ccb
752 changeset: 1:d32277701ccb
736 branch: test
753 branch: test
737 user: test
754 user: test
738 date: Thu Jan 01 00:00:00 1970 +0000
755 date: Thu Jan 01 00:00:00 1970 +0000
739 summary: commit on test
756 summary: commit on test
740
757
741 changeset: 0:24427303d56f
758 changeset: 0:24427303d56f
742 user: test
759 user: test
743 date: Thu Jan 01 00:00:00 1970 +0000
760 date: Thu Jan 01 00:00:00 1970 +0000
744 summary: commit on default
761 summary: commit on default
745
762
746
763
747
764
748 log -b default -b .
765 log -b default -b .
749
766
750 $ hg log -b default -b .
767 $ hg log -b default -b .
751 changeset: 3:f5d8de11c2e2
768 changeset: 3:f5d8de11c2e2
752 branch: test
769 branch: test
753 tag: tip
770 tag: tip
754 parent: 1:d32277701ccb
771 parent: 1:d32277701ccb
755 user: test
772 user: test
756 date: Thu Jan 01 00:00:00 1970 +0000
773 date: Thu Jan 01 00:00:00 1970 +0000
757 summary: commit on test
774 summary: commit on test
758
775
759 changeset: 2:c3a4f03cc9a7
776 changeset: 2:c3a4f03cc9a7
760 parent: 0:24427303d56f
777 parent: 0:24427303d56f
761 user: test
778 user: test
762 date: Thu Jan 01 00:00:00 1970 +0000
779 date: Thu Jan 01 00:00:00 1970 +0000
763 summary: commit on default
780 summary: commit on default
764
781
765 changeset: 1:d32277701ccb
782 changeset: 1:d32277701ccb
766 branch: test
783 branch: test
767 user: test
784 user: test
768 date: Thu Jan 01 00:00:00 1970 +0000
785 date: Thu Jan 01 00:00:00 1970 +0000
769 summary: commit on test
786 summary: commit on test
770
787
771 changeset: 0:24427303d56f
788 changeset: 0:24427303d56f
772 user: test
789 user: test
773 date: Thu Jan 01 00:00:00 1970 +0000
790 date: Thu Jan 01 00:00:00 1970 +0000
774 summary: commit on default
791 summary: commit on default
775
792
776
793
777
794
778 log -b . -b test
795 log -b . -b test
779
796
780 $ hg log -b . -b test
797 $ hg log -b . -b test
781 changeset: 3:f5d8de11c2e2
798 changeset: 3:f5d8de11c2e2
782 branch: test
799 branch: test
783 tag: tip
800 tag: tip
784 parent: 1:d32277701ccb
801 parent: 1:d32277701ccb
785 user: test
802 user: test
786 date: Thu Jan 01 00:00:00 1970 +0000
803 date: Thu Jan 01 00:00:00 1970 +0000
787 summary: commit on test
804 summary: commit on test
788
805
789 changeset: 1:d32277701ccb
806 changeset: 1:d32277701ccb
790 branch: test
807 branch: test
791 user: test
808 user: test
792 date: Thu Jan 01 00:00:00 1970 +0000
809 date: Thu Jan 01 00:00:00 1970 +0000
793 summary: commit on test
810 summary: commit on test
794
811
795
812
796
813
797 log -b 2
814 log -b 2
798
815
799 $ hg log -b 2
816 $ hg log -b 2
800 changeset: 2:c3a4f03cc9a7
817 changeset: 2:c3a4f03cc9a7
801 parent: 0:24427303d56f
818 parent: 0:24427303d56f
802 user: test
819 user: test
803 date: Thu Jan 01 00:00:00 1970 +0000
820 date: Thu Jan 01 00:00:00 1970 +0000
804 summary: commit on default
821 summary: commit on default
805
822
806 changeset: 0:24427303d56f
823 changeset: 0:24427303d56f
807 user: test
824 user: test
808 date: Thu Jan 01 00:00:00 1970 +0000
825 date: Thu Jan 01 00:00:00 1970 +0000
809 summary: commit on default
826 summary: commit on default
810
827
811
828
812
829
813 log -p --cwd dir (in subdir)
830 log -p --cwd dir (in subdir)
814
831
815 $ mkdir dir
832 $ mkdir dir
816 $ hg log -p --cwd dir
833 $ hg log -p --cwd dir
817 changeset: 3:f5d8de11c2e2
834 changeset: 3:f5d8de11c2e2
818 branch: test
835 branch: test
819 tag: tip
836 tag: tip
820 parent: 1:d32277701ccb
837 parent: 1:d32277701ccb
821 user: test
838 user: test
822 date: Thu Jan 01 00:00:00 1970 +0000
839 date: Thu Jan 01 00:00:00 1970 +0000
823 summary: commit on test
840 summary: commit on test
824
841
825 diff -r d32277701ccb -r f5d8de11c2e2 c
842 diff -r d32277701ccb -r f5d8de11c2e2 c
826 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
843 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
827 +++ b/c Thu Jan 01 00:00:00 1970 +0000
844 +++ b/c Thu Jan 01 00:00:00 1970 +0000
828 @@ -0,0 +1,1 @@
845 @@ -0,0 +1,1 @@
829 +c
846 +c
830
847
831 changeset: 2:c3a4f03cc9a7
848 changeset: 2:c3a4f03cc9a7
832 parent: 0:24427303d56f
849 parent: 0:24427303d56f
833 user: test
850 user: test
834 date: Thu Jan 01 00:00:00 1970 +0000
851 date: Thu Jan 01 00:00:00 1970 +0000
835 summary: commit on default
852 summary: commit on default
836
853
837 diff -r 24427303d56f -r c3a4f03cc9a7 c
854 diff -r 24427303d56f -r c3a4f03cc9a7 c
838 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
855 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
839 +++ b/c Thu Jan 01 00:00:00 1970 +0000
856 +++ b/c Thu Jan 01 00:00:00 1970 +0000
840 @@ -0,0 +1,1 @@
857 @@ -0,0 +1,1 @@
841 +c
858 +c
842
859
843 changeset: 1:d32277701ccb
860 changeset: 1:d32277701ccb
844 branch: test
861 branch: test
845 user: test
862 user: test
846 date: Thu Jan 01 00:00:00 1970 +0000
863 date: Thu Jan 01 00:00:00 1970 +0000
847 summary: commit on test
864 summary: commit on test
848
865
849 diff -r 24427303d56f -r d32277701ccb b
866 diff -r 24427303d56f -r d32277701ccb b
850 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
867 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
851 +++ b/b Thu Jan 01 00:00:00 1970 +0000
868 +++ b/b Thu Jan 01 00:00:00 1970 +0000
852 @@ -0,0 +1,1 @@
869 @@ -0,0 +1,1 @@
853 +b
870 +b
854
871
855 changeset: 0:24427303d56f
872 changeset: 0:24427303d56f
856 user: test
873 user: test
857 date: Thu Jan 01 00:00:00 1970 +0000
874 date: Thu Jan 01 00:00:00 1970 +0000
858 summary: commit on default
875 summary: commit on default
859
876
860 diff -r 000000000000 -r 24427303d56f a
877 diff -r 000000000000 -r 24427303d56f a
861 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
878 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
862 +++ b/a Thu Jan 01 00:00:00 1970 +0000
879 +++ b/a Thu Jan 01 00:00:00 1970 +0000
863 @@ -0,0 +1,1 @@
880 @@ -0,0 +1,1 @@
864 +a
881 +a
865
882
866
883
867
884
868 log -p -R repo
885 log -p -R repo
869
886
870 $ cd dir
887 $ cd dir
871 $ hg log -p -R .. ../a
888 $ hg log -p -R .. ../a
872 changeset: 0:24427303d56f
889 changeset: 0:24427303d56f
873 user: test
890 user: test
874 date: Thu Jan 01 00:00:00 1970 +0000
891 date: Thu Jan 01 00:00:00 1970 +0000
875 summary: commit on default
892 summary: commit on default
876
893
877 diff -r 000000000000 -r 24427303d56f a
894 diff -r 000000000000 -r 24427303d56f a
878 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
895 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
879 +++ b/a Thu Jan 01 00:00:00 1970 +0000
896 +++ b/a Thu Jan 01 00:00:00 1970 +0000
880 @@ -0,0 +1,1 @@
897 @@ -0,0 +1,1 @@
881 +a
898 +a
882
899
883
900
884
901
885 $ cd ..
902 $ cd ..
886 $ hg init follow2
903 $ hg init follow2
887 $ cd follow2
904 $ cd follow2
888
905
889
906
890 # Build the following history:
907 # Build the following history:
891 # tip - o - x - o - x - x
908 # tip - o - x - o - x - x
892 # \ /
909 # \ /
893 # o - o - o - x
910 # o - o - o - x
894 # \ /
911 # \ /
895 # o
912 # o
896 #
913 #
897 # Where "o" is a revision containing "foo" and
914 # Where "o" is a revision containing "foo" and
898 # "x" is a revision without "foo"
915 # "x" is a revision without "foo"
899
916
900 $ touch init
917 $ touch init
901 $ hg ci -A -m "init, unrelated"
918 $ hg ci -A -m "init, unrelated"
902 adding init
919 adding init
903 $ echo 'foo' > init
920 $ echo 'foo' > init
904 $ hg ci -m "change, unrelated"
921 $ hg ci -m "change, unrelated"
905 $ echo 'foo' > foo
922 $ echo 'foo' > foo
906 $ hg ci -A -m "add unrelated old foo"
923 $ hg ci -A -m "add unrelated old foo"
907 adding foo
924 adding foo
908 $ hg rm foo
925 $ hg rm foo
909 $ hg ci -m "delete foo, unrelated"
926 $ hg ci -m "delete foo, unrelated"
910 $ echo 'related' > foo
927 $ echo 'related' > foo
911 $ hg ci -A -m "add foo, related"
928 $ hg ci -A -m "add foo, related"
912 adding foo
929 adding foo
913
930
914 $ hg up 0
931 $ hg up 0
915 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
932 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
916 $ touch branch
933 $ touch branch
917 $ hg ci -A -m "first branch, unrelated"
934 $ hg ci -A -m "first branch, unrelated"
918 adding branch
935 adding branch
919 created new head
936 created new head
920 $ touch foo
937 $ touch foo
921 $ hg ci -A -m "create foo, related"
938 $ hg ci -A -m "create foo, related"
922 adding foo
939 adding foo
923 $ echo 'change' > foo
940 $ echo 'change' > foo
924 $ hg ci -m "change foo, related"
941 $ hg ci -m "change foo, related"
925
942
926 $ hg up 6
943 $ hg up 6
927 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
944 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
928 $ echo 'change foo in branch' > foo
945 $ echo 'change foo in branch' > foo
929 $ hg ci -m "change foo in branch, related"
946 $ hg ci -m "change foo in branch, related"
930 created new head
947 created new head
931 $ hg merge 7
948 $ hg merge 7
932 merging foo
949 merging foo
933 warning: conflicts during merge.
950 warning: conflicts during merge.
934 merging foo incomplete! (edit conflicts, then use 'hg resolve --mark')
951 merging foo incomplete! (edit conflicts, then use 'hg resolve --mark')
935 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
952 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
936 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
953 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
937 [1]
954 [1]
938 $ echo 'merge 1' > foo
955 $ echo 'merge 1' > foo
939 $ hg resolve -m foo
956 $ hg resolve -m foo
940 $ hg ci -m "First merge, related"
957 $ hg ci -m "First merge, related"
941
958
942 $ hg merge 4
959 $ hg merge 4
943 merging foo
960 merging foo
944 warning: conflicts during merge.
961 warning: conflicts during merge.
945 merging foo incomplete! (edit conflicts, then use 'hg resolve --mark')
962 merging foo incomplete! (edit conflicts, then use 'hg resolve --mark')
946 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
963 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
947 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
964 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
948 [1]
965 [1]
949 $ echo 'merge 2' > foo
966 $ echo 'merge 2' > foo
950 $ hg resolve -m foo
967 $ hg resolve -m foo
951 $ hg ci -m "Last merge, related"
968 $ hg ci -m "Last merge, related"
952
969
953 $ hg --config "extensions.graphlog=" glog
970 $ hg --config "extensions.graphlog=" glog
954 @ changeset: 10:4dae8563d2c5
971 @ changeset: 10:4dae8563d2c5
955 |\ tag: tip
972 |\ tag: tip
956 | | parent: 9:7b35701b003e
973 | | parent: 9:7b35701b003e
957 | | parent: 4:88176d361b69
974 | | parent: 4:88176d361b69
958 | | user: test
975 | | user: test
959 | | date: Thu Jan 01 00:00:00 1970 +0000
976 | | date: Thu Jan 01 00:00:00 1970 +0000
960 | | summary: Last merge, related
977 | | summary: Last merge, related
961 | |
978 | |
962 | o changeset: 9:7b35701b003e
979 | o changeset: 9:7b35701b003e
963 | |\ parent: 8:e5416ad8a855
980 | |\ parent: 8:e5416ad8a855
964 | | | parent: 7:87fe3144dcfa
981 | | | parent: 7:87fe3144dcfa
965 | | | user: test
982 | | | user: test
966 | | | date: Thu Jan 01 00:00:00 1970 +0000
983 | | | date: Thu Jan 01 00:00:00 1970 +0000
967 | | | summary: First merge, related
984 | | | summary: First merge, related
968 | | |
985 | | |
969 | | o changeset: 8:e5416ad8a855
986 | | o changeset: 8:e5416ad8a855
970 | | | parent: 6:dc6c325fe5ee
987 | | | parent: 6:dc6c325fe5ee
971 | | | user: test
988 | | | user: test
972 | | | date: Thu Jan 01 00:00:00 1970 +0000
989 | | | date: Thu Jan 01 00:00:00 1970 +0000
973 | | | summary: change foo in branch, related
990 | | | summary: change foo in branch, related
974 | | |
991 | | |
975 | o | changeset: 7:87fe3144dcfa
992 | o | changeset: 7:87fe3144dcfa
976 | |/ user: test
993 | |/ user: test
977 | | date: Thu Jan 01 00:00:00 1970 +0000
994 | | date: Thu Jan 01 00:00:00 1970 +0000
978 | | summary: change foo, related
995 | | summary: change foo, related
979 | |
996 | |
980 | o changeset: 6:dc6c325fe5ee
997 | o changeset: 6:dc6c325fe5ee
981 | | user: test
998 | | user: test
982 | | date: Thu Jan 01 00:00:00 1970 +0000
999 | | date: Thu Jan 01 00:00:00 1970 +0000
983 | | summary: create foo, related
1000 | | summary: create foo, related
984 | |
1001 | |
985 | o changeset: 5:73db34516eb9
1002 | o changeset: 5:73db34516eb9
986 | | parent: 0:e87515fd044a
1003 | | parent: 0:e87515fd044a
987 | | user: test
1004 | | user: test
988 | | date: Thu Jan 01 00:00:00 1970 +0000
1005 | | date: Thu Jan 01 00:00:00 1970 +0000
989 | | summary: first branch, unrelated
1006 | | summary: first branch, unrelated
990 | |
1007 | |
991 o | changeset: 4:88176d361b69
1008 o | changeset: 4:88176d361b69
992 | | user: test
1009 | | user: test
993 | | date: Thu Jan 01 00:00:00 1970 +0000
1010 | | date: Thu Jan 01 00:00:00 1970 +0000
994 | | summary: add foo, related
1011 | | summary: add foo, related
995 | |
1012 | |
996 o | changeset: 3:dd78ae4afb56
1013 o | changeset: 3:dd78ae4afb56
997 | | user: test
1014 | | user: test
998 | | date: Thu Jan 01 00:00:00 1970 +0000
1015 | | date: Thu Jan 01 00:00:00 1970 +0000
999 | | summary: delete foo, unrelated
1016 | | summary: delete foo, unrelated
1000 | |
1017 | |
1001 o | changeset: 2:c4c64aedf0f7
1018 o | changeset: 2:c4c64aedf0f7
1002 | | user: test
1019 | | user: test
1003 | | date: Thu Jan 01 00:00:00 1970 +0000
1020 | | date: Thu Jan 01 00:00:00 1970 +0000
1004 | | summary: add unrelated old foo
1021 | | summary: add unrelated old foo
1005 | |
1022 | |
1006 o | changeset: 1:e5faa7440653
1023 o | changeset: 1:e5faa7440653
1007 |/ user: test
1024 |/ user: test
1008 | date: Thu Jan 01 00:00:00 1970 +0000
1025 | date: Thu Jan 01 00:00:00 1970 +0000
1009 | summary: change, unrelated
1026 | summary: change, unrelated
1010 |
1027 |
1011 o changeset: 0:e87515fd044a
1028 o changeset: 0:e87515fd044a
1012 user: test
1029 user: test
1013 date: Thu Jan 01 00:00:00 1970 +0000
1030 date: Thu Jan 01 00:00:00 1970 +0000
1014 summary: init, unrelated
1031 summary: init, unrelated
1015
1032
1016
1033
1017 $ hg --traceback log -f foo
1034 $ hg --traceback log -f foo
1018 changeset: 10:4dae8563d2c5
1035 changeset: 10:4dae8563d2c5
1019 tag: tip
1036 tag: tip
1020 parent: 9:7b35701b003e
1037 parent: 9:7b35701b003e
1021 parent: 4:88176d361b69
1038 parent: 4:88176d361b69
1022 user: test
1039 user: test
1023 date: Thu Jan 01 00:00:00 1970 +0000
1040 date: Thu Jan 01 00:00:00 1970 +0000
1024 summary: Last merge, related
1041 summary: Last merge, related
1025
1042
1026 changeset: 9:7b35701b003e
1043 changeset: 9:7b35701b003e
1027 parent: 8:e5416ad8a855
1044 parent: 8:e5416ad8a855
1028 parent: 7:87fe3144dcfa
1045 parent: 7:87fe3144dcfa
1029 user: test
1046 user: test
1030 date: Thu Jan 01 00:00:00 1970 +0000
1047 date: Thu Jan 01 00:00:00 1970 +0000
1031 summary: First merge, related
1048 summary: First merge, related
1032
1049
1033 changeset: 8:e5416ad8a855
1050 changeset: 8:e5416ad8a855
1034 parent: 6:dc6c325fe5ee
1051 parent: 6:dc6c325fe5ee
1035 user: test
1052 user: test
1036 date: Thu Jan 01 00:00:00 1970 +0000
1053 date: Thu Jan 01 00:00:00 1970 +0000
1037 summary: change foo in branch, related
1054 summary: change foo in branch, related
1038
1055
1039 changeset: 7:87fe3144dcfa
1056 changeset: 7:87fe3144dcfa
1040 user: test
1057 user: test
1041 date: Thu Jan 01 00:00:00 1970 +0000
1058 date: Thu Jan 01 00:00:00 1970 +0000
1042 summary: change foo, related
1059 summary: change foo, related
1043
1060
1044 changeset: 6:dc6c325fe5ee
1061 changeset: 6:dc6c325fe5ee
1045 user: test
1062 user: test
1046 date: Thu Jan 01 00:00:00 1970 +0000
1063 date: Thu Jan 01 00:00:00 1970 +0000
1047 summary: create foo, related
1064 summary: create foo, related
1048
1065
1049 changeset: 4:88176d361b69
1066 changeset: 4:88176d361b69
1050 user: test
1067 user: test
1051 date: Thu Jan 01 00:00:00 1970 +0000
1068 date: Thu Jan 01 00:00:00 1970 +0000
1052 summary: add foo, related
1069 summary: add foo, related
1053
1070
1054
1071
1055 Also check when maxrev < lastrevfilelog
1072 Also check when maxrev < lastrevfilelog
1056
1073
1057 $ hg --traceback log -f -r4 foo
1074 $ hg --traceback log -f -r4 foo
1058 changeset: 4:88176d361b69
1075 changeset: 4:88176d361b69
1059 user: test
1076 user: test
1060 date: Thu Jan 01 00:00:00 1970 +0000
1077 date: Thu Jan 01 00:00:00 1970 +0000
1061 summary: add foo, related
1078 summary: add foo, related
1062
1079
1063
1080
1064 Issue2383: hg log showing _less_ differences than hg diff
1081 Issue2383: hg log showing _less_ differences than hg diff
1065
1082
1066 $ hg init issue2383
1083 $ hg init issue2383
1067 $ cd issue2383
1084 $ cd issue2383
1068
1085
1069 Create a test repo:
1086 Create a test repo:
1070
1087
1071 $ echo a > a
1088 $ echo a > a
1072 $ hg ci -Am0
1089 $ hg ci -Am0
1073 adding a
1090 adding a
1074 $ echo b > b
1091 $ echo b > b
1075 $ hg ci -Am1
1092 $ hg ci -Am1
1076 adding b
1093 adding b
1077 $ hg co 0
1094 $ hg co 0
1078 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1095 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1079 $ echo b > a
1096 $ echo b > a
1080 $ hg ci -m2
1097 $ hg ci -m2
1081 created new head
1098 created new head
1082
1099
1083 Merge:
1100 Merge:
1084
1101
1085 $ hg merge
1102 $ hg merge
1086 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1103 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1087 (branch merge, don't forget to commit)
1104 (branch merge, don't forget to commit)
1088
1105
1089 Make sure there's a file listed in the merge to trigger the bug:
1106 Make sure there's a file listed in the merge to trigger the bug:
1090
1107
1091 $ echo c > a
1108 $ echo c > a
1092 $ hg ci -m3
1109 $ hg ci -m3
1093
1110
1094 Two files shown here in diff:
1111 Two files shown here in diff:
1095
1112
1096 $ hg diff --rev 2:3
1113 $ hg diff --rev 2:3
1097 diff -r b09be438c43a -r 8e07aafe1edc a
1114 diff -r b09be438c43a -r 8e07aafe1edc a
1098 --- a/a Thu Jan 01 00:00:00 1970 +0000
1115 --- a/a Thu Jan 01 00:00:00 1970 +0000
1099 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1116 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1100 @@ -1,1 +1,1 @@
1117 @@ -1,1 +1,1 @@
1101 -b
1118 -b
1102 +c
1119 +c
1103 diff -r b09be438c43a -r 8e07aafe1edc b
1120 diff -r b09be438c43a -r 8e07aafe1edc b
1104 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1121 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1105 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1122 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1106 @@ -0,0 +1,1 @@
1123 @@ -0,0 +1,1 @@
1107 +b
1124 +b
1108
1125
1109 Diff here should be the same:
1126 Diff here should be the same:
1110
1127
1111 $ hg log -vpr 3
1128 $ hg log -vpr 3
1112 changeset: 3:8e07aafe1edc
1129 changeset: 3:8e07aafe1edc
1113 tag: tip
1130 tag: tip
1114 parent: 2:b09be438c43a
1131 parent: 2:b09be438c43a
1115 parent: 1:925d80f479bb
1132 parent: 1:925d80f479bb
1116 user: test
1133 user: test
1117 date: Thu Jan 01 00:00:00 1970 +0000
1134 date: Thu Jan 01 00:00:00 1970 +0000
1118 files: a
1135 files: a
1119 description:
1136 description:
1120 3
1137 3
1121
1138
1122
1139
1123 diff -r b09be438c43a -r 8e07aafe1edc a
1140 diff -r b09be438c43a -r 8e07aafe1edc a
1124 --- a/a Thu Jan 01 00:00:00 1970 +0000
1141 --- a/a Thu Jan 01 00:00:00 1970 +0000
1125 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1142 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1126 @@ -1,1 +1,1 @@
1143 @@ -1,1 +1,1 @@
1127 -b
1144 -b
1128 +c
1145 +c
1129 diff -r b09be438c43a -r 8e07aafe1edc b
1146 diff -r b09be438c43a -r 8e07aafe1edc b
1130 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1147 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1131 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1148 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1132 @@ -0,0 +1,1 @@
1149 @@ -0,0 +1,1 @@
1133 +b
1150 +b
1134
1151
1135 $ cd ..
1152 $ cd ..
1136
1153
1137 'hg log -r rev fn' when last(filelog(fn)) != rev
1154 'hg log -r rev fn' when last(filelog(fn)) != rev
1138
1155
1139 $ hg init simplelog; cd simplelog
1156 $ hg init simplelog; cd simplelog
1140 $ echo f > a
1157 $ echo f > a
1141 $ hg ci -Am'a' -d '0 0'
1158 $ hg ci -Am'a' -d '0 0'
1142 adding a
1159 adding a
1143 $ echo f >> a
1160 $ echo f >> a
1144 $ hg ci -Am'a bis' -d '1 0'
1161 $ hg ci -Am'a bis' -d '1 0'
1145
1162
1146 $ hg log -r0 a
1163 $ hg log -r0 a
1147 changeset: 0:9f758d63dcde
1164 changeset: 0:9f758d63dcde
1148 user: test
1165 user: test
1149 date: Thu Jan 01 00:00:00 1970 +0000
1166 date: Thu Jan 01 00:00:00 1970 +0000
1150 summary: a
1167 summary: a
1151
1168
1152 $ cat > $HGTMP/testhidden.py << EOF
1169 $ cat > $HGTMP/testhidden.py << EOF
1153 > def reposetup(ui, repo):
1170 > def reposetup(ui, repo):
1154 > for line in repo.opener('hidden'):
1171 > for line in repo.opener('hidden'):
1155 > ctx = repo[line.strip()]
1172 > ctx = repo[line.strip()]
1156 > repo.changelog.hiddenrevs.add(ctx.rev())
1173 > repo.changelog.hiddenrevs.add(ctx.rev())
1157 > EOF
1174 > EOF
1158 $ echo '[extensions]' >> $HGRCPATH
1175 $ echo '[extensions]' >> $HGRCPATH
1159 $ echo "hidden=$HGTMP/testhidden.py" >> $HGRCPATH
1176 $ echo "hidden=$HGTMP/testhidden.py" >> $HGRCPATH
1160 $ touch .hg/hidden
1177 $ touch .hg/hidden
1161 $ hg log --template='{rev}:{node}\n'
1178 $ hg log --template='{rev}:{node}\n'
1162 1:a765632148dc55d38c35c4f247c618701886cb2f
1179 1:a765632148dc55d38c35c4f247c618701886cb2f
1163 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1180 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1164 $ echo a765632148dc55d38c35c4f247c618701886cb2f > .hg/hidden
1181 $ echo a765632148dc55d38c35c4f247c618701886cb2f > .hg/hidden
1165 $ hg log --template='{rev}:{node}\n'
1182 $ hg log --template='{rev}:{node}\n'
1166 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1183 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1167 $ hg log --template='{rev}:{node}\n' --hidden
1184 $ hg log --template='{rev}:{node}\n' --hidden
1168 1:a765632148dc55d38c35c4f247c618701886cb2f
1185 1:a765632148dc55d38c35c4f247c618701886cb2f
1169 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1186 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05
1170
1187
1171 clear extensions configuration
1188 clear extensions configuration
1172 $ echo '[extensions]' >> $HGRCPATH
1189 $ echo '[extensions]' >> $HGRCPATH
1173 $ echo "hidden=!" >> $HGRCPATH
1190 $ echo "hidden=!" >> $HGRCPATH
1174 $ cd ..
1191 $ cd ..
1175
1192
1176 test -u/-k for problematic encoding
1193 test -u/-k for problematic encoding
1177 # unicode: cp932:
1194 # unicode: cp932:
1178 # u30A2 0x83 0x41(= 'A')
1195 # u30A2 0x83 0x41(= 'A')
1179 # u30C2 0x83 0x61(= 'a')
1196 # u30C2 0x83 0x61(= 'a')
1180
1197
1181 $ hg init problematicencoding
1198 $ hg init problematicencoding
1182 $ cd problematicencoding
1199 $ cd problematicencoding
1183
1200
1184 $ python > setup.sh <<EOF
1201 $ python > setup.sh <<EOF
1185 > print u'''
1202 > print u'''
1186 > echo a > text
1203 > echo a > text
1187 > hg add text
1204 > hg add text
1188 > hg --encoding utf-8 commit -u '\u30A2' -m none
1205 > hg --encoding utf-8 commit -u '\u30A2' -m none
1189 > echo b > text
1206 > echo b > text
1190 > hg --encoding utf-8 commit -u '\u30C2' -m none
1207 > hg --encoding utf-8 commit -u '\u30C2' -m none
1191 > echo c > text
1208 > echo c > text
1192 > hg --encoding utf-8 commit -u none -m '\u30A2'
1209 > hg --encoding utf-8 commit -u none -m '\u30A2'
1193 > echo d > text
1210 > echo d > text
1194 > hg --encoding utf-8 commit -u none -m '\u30C2'
1211 > hg --encoding utf-8 commit -u none -m '\u30C2'
1195 > '''.encode('utf-8')
1212 > '''.encode('utf-8')
1196 > EOF
1213 > EOF
1197 $ sh < setup.sh
1214 $ sh < setup.sh
1198
1215
1199 test in problematic encoding
1216 test in problematic encoding
1200 $ python > test.sh <<EOF
1217 $ python > test.sh <<EOF
1201 > print u'''
1218 > print u'''
1202 > hg --encoding cp932 log --template '{rev}\\n' -u '\u30A2'
1219 > hg --encoding cp932 log --template '{rev}\\n' -u '\u30A2'
1203 > echo ====
1220 > echo ====
1204 > hg --encoding cp932 log --template '{rev}\\n' -u '\u30C2'
1221 > hg --encoding cp932 log --template '{rev}\\n' -u '\u30C2'
1205 > echo ====
1222 > echo ====
1206 > hg --encoding cp932 log --template '{rev}\\n' -k '\u30A2'
1223 > hg --encoding cp932 log --template '{rev}\\n' -k '\u30A2'
1207 > echo ====
1224 > echo ====
1208 > hg --encoding cp932 log --template '{rev}\\n' -k '\u30C2'
1225 > hg --encoding cp932 log --template '{rev}\\n' -k '\u30C2'
1209 > '''.encode('cp932')
1226 > '''.encode('cp932')
1210 > EOF
1227 > EOF
1211 $ sh < test.sh
1228 $ sh < test.sh
1212 0
1229 0
1213 ====
1230 ====
1214 1
1231 1
1215 ====
1232 ====
1216 2
1233 2
1217 0
1234 0
1218 ====
1235 ====
1219 3
1236 3
1220 1
1237 1
1221
1238
1222 $ cd ..
1239 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now