##// END OF EJS Templates
heads: fix templating of headers again (issue2130)...
Simon Howkins -
r11465:ace5bd98 stable
parent child Browse files
Show More
@@ -1,1242 +1,1241 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, glob, tempfile
10 import os, sys, errno, re, glob, tempfile
11 import util, templater, patch, error, encoding, templatekw
11 import util, templater, patch, error, encoding, templatekw
12 import match as _match
12 import match as _match
13 import similar, revset
13 import similar, revset
14
14
15 revrangesep = ':'
15 revrangesep = ':'
16
16
17 def parsealiases(cmd):
17 def parsealiases(cmd):
18 return cmd.lstrip("^").split("|")
18 return cmd.lstrip("^").split("|")
19
19
20 def findpossible(cmd, table, strict=False):
20 def findpossible(cmd, table, strict=False):
21 """
21 """
22 Return cmd -> (aliases, command table entry)
22 Return cmd -> (aliases, command table entry)
23 for each matching command.
23 for each matching command.
24 Return debug commands (or their aliases) only if no normal command matches.
24 Return debug commands (or their aliases) only if no normal command matches.
25 """
25 """
26 choice = {}
26 choice = {}
27 debugchoice = {}
27 debugchoice = {}
28 for e in table.keys():
28 for e in table.keys():
29 aliases = parsealiases(e)
29 aliases = parsealiases(e)
30 found = None
30 found = None
31 if cmd in aliases:
31 if cmd in aliases:
32 found = cmd
32 found = cmd
33 elif not strict:
33 elif not strict:
34 for a in aliases:
34 for a in aliases:
35 if a.startswith(cmd):
35 if a.startswith(cmd):
36 found = a
36 found = a
37 break
37 break
38 if found is not None:
38 if found is not None:
39 if aliases[0].startswith("debug") or found.startswith("debug"):
39 if aliases[0].startswith("debug") or found.startswith("debug"):
40 debugchoice[found] = (aliases, table[e])
40 debugchoice[found] = (aliases, table[e])
41 else:
41 else:
42 choice[found] = (aliases, table[e])
42 choice[found] = (aliases, table[e])
43
43
44 if not choice and debugchoice:
44 if not choice and debugchoice:
45 choice = debugchoice
45 choice = debugchoice
46
46
47 return choice
47 return choice
48
48
49 def findcmd(cmd, table, strict=True):
49 def findcmd(cmd, table, strict=True):
50 """Return (aliases, command table entry) for command string."""
50 """Return (aliases, command table entry) for command string."""
51 choice = findpossible(cmd, table, strict)
51 choice = findpossible(cmd, table, strict)
52
52
53 if cmd in choice:
53 if cmd in choice:
54 return choice[cmd]
54 return choice[cmd]
55
55
56 if len(choice) > 1:
56 if len(choice) > 1:
57 clist = choice.keys()
57 clist = choice.keys()
58 clist.sort()
58 clist.sort()
59 raise error.AmbiguousCommand(cmd, clist)
59 raise error.AmbiguousCommand(cmd, clist)
60
60
61 if choice:
61 if choice:
62 return choice.values()[0]
62 return choice.values()[0]
63
63
64 raise error.UnknownCommand(cmd)
64 raise error.UnknownCommand(cmd)
65
65
66 def findrepo(p):
66 def findrepo(p):
67 while not os.path.isdir(os.path.join(p, ".hg")):
67 while not os.path.isdir(os.path.join(p, ".hg")):
68 oldp, p = p, os.path.dirname(p)
68 oldp, p = p, os.path.dirname(p)
69 if p == oldp:
69 if p == oldp:
70 return None
70 return None
71
71
72 return p
72 return p
73
73
74 def bail_if_changed(repo):
74 def bail_if_changed(repo):
75 if repo.dirstate.parents()[1] != nullid:
75 if repo.dirstate.parents()[1] != nullid:
76 raise util.Abort(_('outstanding uncommitted merge'))
76 raise util.Abort(_('outstanding uncommitted merge'))
77 modified, added, removed, deleted = repo.status()[:4]
77 modified, added, removed, deleted = repo.status()[:4]
78 if modified or added or removed or deleted:
78 if modified or added or removed or deleted:
79 raise util.Abort(_("outstanding uncommitted changes"))
79 raise util.Abort(_("outstanding uncommitted changes"))
80
80
81 def logmessage(opts):
81 def logmessage(opts):
82 """ get the log message according to -m and -l option """
82 """ get the log message according to -m and -l option """
83 message = opts.get('message')
83 message = opts.get('message')
84 logfile = opts.get('logfile')
84 logfile = opts.get('logfile')
85
85
86 if message and logfile:
86 if message and logfile:
87 raise util.Abort(_('options --message and --logfile are mutually '
87 raise util.Abort(_('options --message and --logfile are mutually '
88 'exclusive'))
88 'exclusive'))
89 if not message and logfile:
89 if not message and logfile:
90 try:
90 try:
91 if logfile == '-':
91 if logfile == '-':
92 message = sys.stdin.read()
92 message = sys.stdin.read()
93 else:
93 else:
94 message = open(logfile).read()
94 message = open(logfile).read()
95 except IOError, inst:
95 except IOError, inst:
96 raise util.Abort(_("can't read commit message '%s': %s") %
96 raise util.Abort(_("can't read commit message '%s': %s") %
97 (logfile, inst.strerror))
97 (logfile, inst.strerror))
98 return message
98 return message
99
99
100 def loglimit(opts):
100 def loglimit(opts):
101 """get the log limit according to option -l/--limit"""
101 """get the log limit according to option -l/--limit"""
102 limit = opts.get('limit')
102 limit = opts.get('limit')
103 if limit:
103 if limit:
104 try:
104 try:
105 limit = int(limit)
105 limit = int(limit)
106 except ValueError:
106 except ValueError:
107 raise util.Abort(_('limit must be a positive integer'))
107 raise util.Abort(_('limit must be a positive integer'))
108 if limit <= 0:
108 if limit <= 0:
109 raise util.Abort(_('limit must be positive'))
109 raise util.Abort(_('limit must be positive'))
110 else:
110 else:
111 limit = None
111 limit = None
112 return limit
112 return limit
113
113
114 def revpair(repo, revs):
114 def revpair(repo, revs):
115 '''return pair of nodes, given list of revisions. second item can
115 '''return pair of nodes, given list of revisions. second item can
116 be None, meaning use working dir.'''
116 be None, meaning use working dir.'''
117
117
118 def revfix(repo, val, defval):
118 def revfix(repo, val, defval):
119 if not val and val != 0 and defval is not None:
119 if not val and val != 0 and defval is not None:
120 val = defval
120 val = defval
121 return repo.lookup(val)
121 return repo.lookup(val)
122
122
123 if not revs:
123 if not revs:
124 return repo.dirstate.parents()[0], None
124 return repo.dirstate.parents()[0], None
125 end = None
125 end = None
126 if len(revs) == 1:
126 if len(revs) == 1:
127 if revrangesep in revs[0]:
127 if revrangesep in revs[0]:
128 start, end = revs[0].split(revrangesep, 1)
128 start, end = revs[0].split(revrangesep, 1)
129 start = revfix(repo, start, 0)
129 start = revfix(repo, start, 0)
130 end = revfix(repo, end, len(repo) - 1)
130 end = revfix(repo, end, len(repo) - 1)
131 else:
131 else:
132 start = revfix(repo, revs[0], None)
132 start = revfix(repo, revs[0], None)
133 elif len(revs) == 2:
133 elif len(revs) == 2:
134 if revrangesep in revs[0] or revrangesep in revs[1]:
134 if revrangesep in revs[0] or revrangesep in revs[1]:
135 raise util.Abort(_('too many revisions specified'))
135 raise util.Abort(_('too many revisions specified'))
136 start = revfix(repo, revs[0], None)
136 start = revfix(repo, revs[0], None)
137 end = revfix(repo, revs[1], None)
137 end = revfix(repo, revs[1], None)
138 else:
138 else:
139 raise util.Abort(_('too many revisions specified'))
139 raise util.Abort(_('too many revisions specified'))
140 return start, end
140 return start, end
141
141
142 def revrange(repo, revs):
142 def revrange(repo, revs):
143 """Yield revision as strings from a list of revision specifications."""
143 """Yield revision as strings from a list of revision specifications."""
144
144
145 def revfix(repo, val, defval):
145 def revfix(repo, val, defval):
146 if not val and val != 0 and defval is not None:
146 if not val and val != 0 and defval is not None:
147 return defval
147 return defval
148 return repo.changelog.rev(repo.lookup(val))
148 return repo.changelog.rev(repo.lookup(val))
149
149
150 seen, l = set(), []
150 seen, l = set(), []
151 for spec in revs:
151 for spec in revs:
152 # attempt to parse old-style ranges first to deal with
152 # attempt to parse old-style ranges first to deal with
153 # things like old-tag which contain query metacharacters
153 # things like old-tag which contain query metacharacters
154 try:
154 try:
155 if revrangesep in spec:
155 if revrangesep in spec:
156 start, end = spec.split(revrangesep, 1)
156 start, end = spec.split(revrangesep, 1)
157 start = revfix(repo, start, 0)
157 start = revfix(repo, start, 0)
158 end = revfix(repo, end, len(repo) - 1)
158 end = revfix(repo, end, len(repo) - 1)
159 step = start > end and -1 or 1
159 step = start > end and -1 or 1
160 for rev in xrange(start, end + step, step):
160 for rev in xrange(start, end + step, step):
161 if rev in seen:
161 if rev in seen:
162 continue
162 continue
163 seen.add(rev)
163 seen.add(rev)
164 l.append(rev)
164 l.append(rev)
165 continue
165 continue
166 elif spec and spec in repo: # single unquoted rev
166 elif spec and spec in repo: # single unquoted rev
167 rev = revfix(repo, spec, None)
167 rev = revfix(repo, spec, None)
168 if rev in seen:
168 if rev in seen:
169 continue
169 continue
170 seen.add(rev)
170 seen.add(rev)
171 l.append(rev)
171 l.append(rev)
172 continue
172 continue
173 except error.RepoLookupError:
173 except error.RepoLookupError:
174 pass
174 pass
175
175
176 # fall through to new-style queries if old-style fails
176 # fall through to new-style queries if old-style fails
177 m = revset.match(spec)
177 m = revset.match(spec)
178 for r in m(repo, range(len(repo))):
178 for r in m(repo, range(len(repo))):
179 if r not in seen:
179 if r not in seen:
180 l.append(r)
180 l.append(r)
181 seen.update(l)
181 seen.update(l)
182
182
183 return l
183 return l
184
184
185 def make_filename(repo, pat, node,
185 def make_filename(repo, pat, node,
186 total=None, seqno=None, revwidth=None, pathname=None):
186 total=None, seqno=None, revwidth=None, pathname=None):
187 node_expander = {
187 node_expander = {
188 'H': lambda: hex(node),
188 'H': lambda: hex(node),
189 'R': lambda: str(repo.changelog.rev(node)),
189 'R': lambda: str(repo.changelog.rev(node)),
190 'h': lambda: short(node),
190 'h': lambda: short(node),
191 }
191 }
192 expander = {
192 expander = {
193 '%': lambda: '%',
193 '%': lambda: '%',
194 'b': lambda: os.path.basename(repo.root),
194 'b': lambda: os.path.basename(repo.root),
195 }
195 }
196
196
197 try:
197 try:
198 if node:
198 if node:
199 expander.update(node_expander)
199 expander.update(node_expander)
200 if node:
200 if node:
201 expander['r'] = (lambda:
201 expander['r'] = (lambda:
202 str(repo.changelog.rev(node)).zfill(revwidth or 0))
202 str(repo.changelog.rev(node)).zfill(revwidth or 0))
203 if total is not None:
203 if total is not None:
204 expander['N'] = lambda: str(total)
204 expander['N'] = lambda: str(total)
205 if seqno is not None:
205 if seqno is not None:
206 expander['n'] = lambda: str(seqno)
206 expander['n'] = lambda: str(seqno)
207 if total is not None and seqno is not None:
207 if total is not None and seqno is not None:
208 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
208 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
209 if pathname is not None:
209 if pathname is not None:
210 expander['s'] = lambda: os.path.basename(pathname)
210 expander['s'] = lambda: os.path.basename(pathname)
211 expander['d'] = lambda: os.path.dirname(pathname) or '.'
211 expander['d'] = lambda: os.path.dirname(pathname) or '.'
212 expander['p'] = lambda: pathname
212 expander['p'] = lambda: pathname
213
213
214 newname = []
214 newname = []
215 patlen = len(pat)
215 patlen = len(pat)
216 i = 0
216 i = 0
217 while i < patlen:
217 while i < patlen:
218 c = pat[i]
218 c = pat[i]
219 if c == '%':
219 if c == '%':
220 i += 1
220 i += 1
221 c = pat[i]
221 c = pat[i]
222 c = expander[c]()
222 c = expander[c]()
223 newname.append(c)
223 newname.append(c)
224 i += 1
224 i += 1
225 return ''.join(newname)
225 return ''.join(newname)
226 except KeyError, inst:
226 except KeyError, inst:
227 raise util.Abort(_("invalid format spec '%%%s' in output filename") %
227 raise util.Abort(_("invalid format spec '%%%s' in output filename") %
228 inst.args[0])
228 inst.args[0])
229
229
230 def make_file(repo, pat, node=None,
230 def make_file(repo, pat, node=None,
231 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
231 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
232
232
233 writable = 'w' in mode or 'a' in mode
233 writable = 'w' in mode or 'a' in mode
234
234
235 if not pat or pat == '-':
235 if not pat or pat == '-':
236 return writable and sys.stdout or sys.stdin
236 return writable and sys.stdout or sys.stdin
237 if hasattr(pat, 'write') and writable:
237 if hasattr(pat, 'write') and writable:
238 return pat
238 return pat
239 if hasattr(pat, 'read') and 'r' in mode:
239 if hasattr(pat, 'read') and 'r' in mode:
240 return pat
240 return pat
241 return open(make_filename(repo, pat, node, total, seqno, revwidth,
241 return open(make_filename(repo, pat, node, total, seqno, revwidth,
242 pathname),
242 pathname),
243 mode)
243 mode)
244
244
245 def expandpats(pats):
245 def expandpats(pats):
246 if not util.expandglobs:
246 if not util.expandglobs:
247 return list(pats)
247 return list(pats)
248 ret = []
248 ret = []
249 for p in pats:
249 for p in pats:
250 kind, name = _match._patsplit(p, None)
250 kind, name = _match._patsplit(p, None)
251 if kind is None:
251 if kind is None:
252 try:
252 try:
253 globbed = glob.glob(name)
253 globbed = glob.glob(name)
254 except re.error:
254 except re.error:
255 globbed = [name]
255 globbed = [name]
256 if globbed:
256 if globbed:
257 ret.extend(globbed)
257 ret.extend(globbed)
258 continue
258 continue
259 ret.append(p)
259 ret.append(p)
260 return ret
260 return ret
261
261
262 def match(repo, pats=[], opts={}, globbed=False, default='relpath'):
262 def match(repo, pats=[], opts={}, globbed=False, default='relpath'):
263 if not globbed and default == 'relpath':
263 if not globbed and default == 'relpath':
264 pats = expandpats(pats or [])
264 pats = expandpats(pats or [])
265 m = _match.match(repo.root, repo.getcwd(), pats,
265 m = _match.match(repo.root, repo.getcwd(), pats,
266 opts.get('include'), opts.get('exclude'), default)
266 opts.get('include'), opts.get('exclude'), default)
267 def badfn(f, msg):
267 def badfn(f, msg):
268 repo.ui.warn("%s: %s\n" % (m.rel(f), msg))
268 repo.ui.warn("%s: %s\n" % (m.rel(f), msg))
269 m.bad = badfn
269 m.bad = badfn
270 return m
270 return m
271
271
272 def matchall(repo):
272 def matchall(repo):
273 return _match.always(repo.root, repo.getcwd())
273 return _match.always(repo.root, repo.getcwd())
274
274
275 def matchfiles(repo, files):
275 def matchfiles(repo, files):
276 return _match.exact(repo.root, repo.getcwd(), files)
276 return _match.exact(repo.root, repo.getcwd(), files)
277
277
278 def addremove(repo, pats=[], opts={}, dry_run=None, similarity=None):
278 def addremove(repo, pats=[], opts={}, dry_run=None, similarity=None):
279 if dry_run is None:
279 if dry_run is None:
280 dry_run = opts.get('dry_run')
280 dry_run = opts.get('dry_run')
281 if similarity is None:
281 if similarity is None:
282 similarity = float(opts.get('similarity') or 0)
282 similarity = float(opts.get('similarity') or 0)
283 # we'd use status here, except handling of symlinks and ignore is tricky
283 # we'd use status here, except handling of symlinks and ignore is tricky
284 added, unknown, deleted, removed = [], [], [], []
284 added, unknown, deleted, removed = [], [], [], []
285 audit_path = util.path_auditor(repo.root)
285 audit_path = util.path_auditor(repo.root)
286 m = match(repo, pats, opts)
286 m = match(repo, pats, opts)
287 for abs in repo.walk(m):
287 for abs in repo.walk(m):
288 target = repo.wjoin(abs)
288 target = repo.wjoin(abs)
289 good = True
289 good = True
290 try:
290 try:
291 audit_path(abs)
291 audit_path(abs)
292 except:
292 except:
293 good = False
293 good = False
294 rel = m.rel(abs)
294 rel = m.rel(abs)
295 exact = m.exact(abs)
295 exact = m.exact(abs)
296 if good and abs not in repo.dirstate:
296 if good and abs not in repo.dirstate:
297 unknown.append(abs)
297 unknown.append(abs)
298 if repo.ui.verbose or not exact:
298 if repo.ui.verbose or not exact:
299 repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
299 repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
300 elif repo.dirstate[abs] != 'r' and (not good or not util.lexists(target)
300 elif repo.dirstate[abs] != 'r' and (not good or not util.lexists(target)
301 or (os.path.isdir(target) and not os.path.islink(target))):
301 or (os.path.isdir(target) and not os.path.islink(target))):
302 deleted.append(abs)
302 deleted.append(abs)
303 if repo.ui.verbose or not exact:
303 if repo.ui.verbose or not exact:
304 repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
304 repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
305 # for finding renames
305 # for finding renames
306 elif repo.dirstate[abs] == 'r':
306 elif repo.dirstate[abs] == 'r':
307 removed.append(abs)
307 removed.append(abs)
308 elif repo.dirstate[abs] == 'a':
308 elif repo.dirstate[abs] == 'a':
309 added.append(abs)
309 added.append(abs)
310 copies = {}
310 copies = {}
311 if similarity > 0:
311 if similarity > 0:
312 for old, new, score in similar.findrenames(repo,
312 for old, new, score in similar.findrenames(repo,
313 added + unknown, removed + deleted, similarity):
313 added + unknown, removed + deleted, similarity):
314 if repo.ui.verbose or not m.exact(old) or not m.exact(new):
314 if repo.ui.verbose or not m.exact(old) or not m.exact(new):
315 repo.ui.status(_('recording removal of %s as rename to %s '
315 repo.ui.status(_('recording removal of %s as rename to %s '
316 '(%d%% similar)\n') %
316 '(%d%% similar)\n') %
317 (m.rel(old), m.rel(new), score * 100))
317 (m.rel(old), m.rel(new), score * 100))
318 copies[new] = old
318 copies[new] = old
319
319
320 if not dry_run:
320 if not dry_run:
321 wctx = repo[None]
321 wctx = repo[None]
322 wlock = repo.wlock()
322 wlock = repo.wlock()
323 try:
323 try:
324 wctx.remove(deleted)
324 wctx.remove(deleted)
325 wctx.add(unknown)
325 wctx.add(unknown)
326 for new, old in copies.iteritems():
326 for new, old in copies.iteritems():
327 wctx.copy(old, new)
327 wctx.copy(old, new)
328 finally:
328 finally:
329 wlock.release()
329 wlock.release()
330
330
331 def copy(ui, repo, pats, opts, rename=False):
331 def copy(ui, repo, pats, opts, rename=False):
332 # called with the repo lock held
332 # called with the repo lock held
333 #
333 #
334 # hgsep => pathname that uses "/" to separate directories
334 # hgsep => pathname that uses "/" to separate directories
335 # ossep => pathname that uses os.sep to separate directories
335 # ossep => pathname that uses os.sep to separate directories
336 cwd = repo.getcwd()
336 cwd = repo.getcwd()
337 targets = {}
337 targets = {}
338 after = opts.get("after")
338 after = opts.get("after")
339 dryrun = opts.get("dry_run")
339 dryrun = opts.get("dry_run")
340 wctx = repo[None]
340 wctx = repo[None]
341
341
342 def walkpat(pat):
342 def walkpat(pat):
343 srcs = []
343 srcs = []
344 badstates = after and '?' or '?r'
344 badstates = after and '?' or '?r'
345 m = match(repo, [pat], opts, globbed=True)
345 m = match(repo, [pat], opts, globbed=True)
346 for abs in repo.walk(m):
346 for abs in repo.walk(m):
347 state = repo.dirstate[abs]
347 state = repo.dirstate[abs]
348 rel = m.rel(abs)
348 rel = m.rel(abs)
349 exact = m.exact(abs)
349 exact = m.exact(abs)
350 if state in badstates:
350 if state in badstates:
351 if exact and state == '?':
351 if exact and state == '?':
352 ui.warn(_('%s: not copying - file is not managed\n') % rel)
352 ui.warn(_('%s: not copying - file is not managed\n') % rel)
353 if exact and state == 'r':
353 if exact and state == 'r':
354 ui.warn(_('%s: not copying - file has been marked for'
354 ui.warn(_('%s: not copying - file has been marked for'
355 ' remove\n') % rel)
355 ' remove\n') % rel)
356 continue
356 continue
357 # abs: hgsep
357 # abs: hgsep
358 # rel: ossep
358 # rel: ossep
359 srcs.append((abs, rel, exact))
359 srcs.append((abs, rel, exact))
360 return srcs
360 return srcs
361
361
362 # abssrc: hgsep
362 # abssrc: hgsep
363 # relsrc: ossep
363 # relsrc: ossep
364 # otarget: ossep
364 # otarget: ossep
365 def copyfile(abssrc, relsrc, otarget, exact):
365 def copyfile(abssrc, relsrc, otarget, exact):
366 abstarget = util.canonpath(repo.root, cwd, otarget)
366 abstarget = util.canonpath(repo.root, cwd, otarget)
367 reltarget = repo.pathto(abstarget, cwd)
367 reltarget = repo.pathto(abstarget, cwd)
368 target = repo.wjoin(abstarget)
368 target = repo.wjoin(abstarget)
369 src = repo.wjoin(abssrc)
369 src = repo.wjoin(abssrc)
370 state = repo.dirstate[abstarget]
370 state = repo.dirstate[abstarget]
371
371
372 # check for collisions
372 # check for collisions
373 prevsrc = targets.get(abstarget)
373 prevsrc = targets.get(abstarget)
374 if prevsrc is not None:
374 if prevsrc is not None:
375 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
375 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
376 (reltarget, repo.pathto(abssrc, cwd),
376 (reltarget, repo.pathto(abssrc, cwd),
377 repo.pathto(prevsrc, cwd)))
377 repo.pathto(prevsrc, cwd)))
378 return
378 return
379
379
380 # check for overwrites
380 # check for overwrites
381 exists = os.path.exists(target)
381 exists = os.path.exists(target)
382 if not after and exists or after and state in 'mn':
382 if not after and exists or after and state in 'mn':
383 if not opts['force']:
383 if not opts['force']:
384 ui.warn(_('%s: not overwriting - file exists\n') %
384 ui.warn(_('%s: not overwriting - file exists\n') %
385 reltarget)
385 reltarget)
386 return
386 return
387
387
388 if after:
388 if after:
389 if not exists:
389 if not exists:
390 if rename:
390 if rename:
391 ui.warn(_('%s: not recording move - %s does not exist\n') %
391 ui.warn(_('%s: not recording move - %s does not exist\n') %
392 (relsrc, reltarget))
392 (relsrc, reltarget))
393 else:
393 else:
394 ui.warn(_('%s: not recording copy - %s does not exist\n') %
394 ui.warn(_('%s: not recording copy - %s does not exist\n') %
395 (relsrc, reltarget))
395 (relsrc, reltarget))
396 return
396 return
397 elif not dryrun:
397 elif not dryrun:
398 try:
398 try:
399 if exists:
399 if exists:
400 os.unlink(target)
400 os.unlink(target)
401 targetdir = os.path.dirname(target) or '.'
401 targetdir = os.path.dirname(target) or '.'
402 if not os.path.isdir(targetdir):
402 if not os.path.isdir(targetdir):
403 os.makedirs(targetdir)
403 os.makedirs(targetdir)
404 util.copyfile(src, target)
404 util.copyfile(src, target)
405 except IOError, inst:
405 except IOError, inst:
406 if inst.errno == errno.ENOENT:
406 if inst.errno == errno.ENOENT:
407 ui.warn(_('%s: deleted in working copy\n') % relsrc)
407 ui.warn(_('%s: deleted in working copy\n') % relsrc)
408 else:
408 else:
409 ui.warn(_('%s: cannot copy - %s\n') %
409 ui.warn(_('%s: cannot copy - %s\n') %
410 (relsrc, inst.strerror))
410 (relsrc, inst.strerror))
411 return True # report a failure
411 return True # report a failure
412
412
413 if ui.verbose or not exact:
413 if ui.verbose or not exact:
414 if rename:
414 if rename:
415 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
415 ui.status(_('moving %s to %s\n') % (relsrc, reltarget))
416 else:
416 else:
417 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
417 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
418
418
419 targets[abstarget] = abssrc
419 targets[abstarget] = abssrc
420
420
421 # fix up dirstate
421 # fix up dirstate
422 origsrc = repo.dirstate.copied(abssrc) or abssrc
422 origsrc = repo.dirstate.copied(abssrc) or abssrc
423 if abstarget == origsrc: # copying back a copy?
423 if abstarget == origsrc: # copying back a copy?
424 if state not in 'mn' and not dryrun:
424 if state not in 'mn' and not dryrun:
425 repo.dirstate.normallookup(abstarget)
425 repo.dirstate.normallookup(abstarget)
426 else:
426 else:
427 if repo.dirstate[origsrc] == 'a' and origsrc == abssrc:
427 if repo.dirstate[origsrc] == 'a' and origsrc == abssrc:
428 if not ui.quiet:
428 if not ui.quiet:
429 ui.warn(_("%s has not been committed yet, so no copy "
429 ui.warn(_("%s has not been committed yet, so no copy "
430 "data will be stored for %s.\n")
430 "data will be stored for %s.\n")
431 % (repo.pathto(origsrc, cwd), reltarget))
431 % (repo.pathto(origsrc, cwd), reltarget))
432 if repo.dirstate[abstarget] in '?r' and not dryrun:
432 if repo.dirstate[abstarget] in '?r' and not dryrun:
433 wctx.add([abstarget])
433 wctx.add([abstarget])
434 elif not dryrun:
434 elif not dryrun:
435 wctx.copy(origsrc, abstarget)
435 wctx.copy(origsrc, abstarget)
436
436
437 if rename and not dryrun:
437 if rename and not dryrun:
438 wctx.remove([abssrc], not after)
438 wctx.remove([abssrc], not after)
439
439
440 # pat: ossep
440 # pat: ossep
441 # dest ossep
441 # dest ossep
442 # srcs: list of (hgsep, hgsep, ossep, bool)
442 # srcs: list of (hgsep, hgsep, ossep, bool)
443 # return: function that takes hgsep and returns ossep
443 # return: function that takes hgsep and returns ossep
444 def targetpathfn(pat, dest, srcs):
444 def targetpathfn(pat, dest, srcs):
445 if os.path.isdir(pat):
445 if os.path.isdir(pat):
446 abspfx = util.canonpath(repo.root, cwd, pat)
446 abspfx = util.canonpath(repo.root, cwd, pat)
447 abspfx = util.localpath(abspfx)
447 abspfx = util.localpath(abspfx)
448 if destdirexists:
448 if destdirexists:
449 striplen = len(os.path.split(abspfx)[0])
449 striplen = len(os.path.split(abspfx)[0])
450 else:
450 else:
451 striplen = len(abspfx)
451 striplen = len(abspfx)
452 if striplen:
452 if striplen:
453 striplen += len(os.sep)
453 striplen += len(os.sep)
454 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
454 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
455 elif destdirexists:
455 elif destdirexists:
456 res = lambda p: os.path.join(dest,
456 res = lambda p: os.path.join(dest,
457 os.path.basename(util.localpath(p)))
457 os.path.basename(util.localpath(p)))
458 else:
458 else:
459 res = lambda p: dest
459 res = lambda p: dest
460 return res
460 return res
461
461
462 # pat: ossep
462 # pat: ossep
463 # dest ossep
463 # dest ossep
464 # srcs: list of (hgsep, hgsep, ossep, bool)
464 # srcs: list of (hgsep, hgsep, ossep, bool)
465 # return: function that takes hgsep and returns ossep
465 # return: function that takes hgsep and returns ossep
466 def targetpathafterfn(pat, dest, srcs):
466 def targetpathafterfn(pat, dest, srcs):
467 if _match.patkind(pat):
467 if _match.patkind(pat):
468 # a mercurial pattern
468 # a mercurial pattern
469 res = lambda p: os.path.join(dest,
469 res = lambda p: os.path.join(dest,
470 os.path.basename(util.localpath(p)))
470 os.path.basename(util.localpath(p)))
471 else:
471 else:
472 abspfx = util.canonpath(repo.root, cwd, pat)
472 abspfx = util.canonpath(repo.root, cwd, pat)
473 if len(abspfx) < len(srcs[0][0]):
473 if len(abspfx) < len(srcs[0][0]):
474 # A directory. Either the target path contains the last
474 # A directory. Either the target path contains the last
475 # component of the source path or it does not.
475 # component of the source path or it does not.
476 def evalpath(striplen):
476 def evalpath(striplen):
477 score = 0
477 score = 0
478 for s in srcs:
478 for s in srcs:
479 t = os.path.join(dest, util.localpath(s[0])[striplen:])
479 t = os.path.join(dest, util.localpath(s[0])[striplen:])
480 if os.path.exists(t):
480 if os.path.exists(t):
481 score += 1
481 score += 1
482 return score
482 return score
483
483
484 abspfx = util.localpath(abspfx)
484 abspfx = util.localpath(abspfx)
485 striplen = len(abspfx)
485 striplen = len(abspfx)
486 if striplen:
486 if striplen:
487 striplen += len(os.sep)
487 striplen += len(os.sep)
488 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
488 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
489 score = evalpath(striplen)
489 score = evalpath(striplen)
490 striplen1 = len(os.path.split(abspfx)[0])
490 striplen1 = len(os.path.split(abspfx)[0])
491 if striplen1:
491 if striplen1:
492 striplen1 += len(os.sep)
492 striplen1 += len(os.sep)
493 if evalpath(striplen1) > score:
493 if evalpath(striplen1) > score:
494 striplen = striplen1
494 striplen = striplen1
495 res = lambda p: os.path.join(dest,
495 res = lambda p: os.path.join(dest,
496 util.localpath(p)[striplen:])
496 util.localpath(p)[striplen:])
497 else:
497 else:
498 # a file
498 # a file
499 if destdirexists:
499 if destdirexists:
500 res = lambda p: os.path.join(dest,
500 res = lambda p: os.path.join(dest,
501 os.path.basename(util.localpath(p)))
501 os.path.basename(util.localpath(p)))
502 else:
502 else:
503 res = lambda p: dest
503 res = lambda p: dest
504 return res
504 return res
505
505
506
506
507 pats = expandpats(pats)
507 pats = expandpats(pats)
508 if not pats:
508 if not pats:
509 raise util.Abort(_('no source or destination specified'))
509 raise util.Abort(_('no source or destination specified'))
510 if len(pats) == 1:
510 if len(pats) == 1:
511 raise util.Abort(_('no destination specified'))
511 raise util.Abort(_('no destination specified'))
512 dest = pats.pop()
512 dest = pats.pop()
513 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
513 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
514 if not destdirexists:
514 if not destdirexists:
515 if len(pats) > 1 or _match.patkind(pats[0]):
515 if len(pats) > 1 or _match.patkind(pats[0]):
516 raise util.Abort(_('with multiple sources, destination must be an '
516 raise util.Abort(_('with multiple sources, destination must be an '
517 'existing directory'))
517 'existing directory'))
518 if util.endswithsep(dest):
518 if util.endswithsep(dest):
519 raise util.Abort(_('destination %s is not a directory') % dest)
519 raise util.Abort(_('destination %s is not a directory') % dest)
520
520
521 tfn = targetpathfn
521 tfn = targetpathfn
522 if after:
522 if after:
523 tfn = targetpathafterfn
523 tfn = targetpathafterfn
524 copylist = []
524 copylist = []
525 for pat in pats:
525 for pat in pats:
526 srcs = walkpat(pat)
526 srcs = walkpat(pat)
527 if not srcs:
527 if not srcs:
528 continue
528 continue
529 copylist.append((tfn(pat, dest, srcs), srcs))
529 copylist.append((tfn(pat, dest, srcs), srcs))
530 if not copylist:
530 if not copylist:
531 raise util.Abort(_('no files to copy'))
531 raise util.Abort(_('no files to copy'))
532
532
533 errors = 0
533 errors = 0
534 for targetpath, srcs in copylist:
534 for targetpath, srcs in copylist:
535 for abssrc, relsrc, exact in srcs:
535 for abssrc, relsrc, exact in srcs:
536 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
536 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
537 errors += 1
537 errors += 1
538
538
539 if errors:
539 if errors:
540 ui.warn(_('(consider using --after)\n'))
540 ui.warn(_('(consider using --after)\n'))
541
541
542 return errors != 0
542 return errors != 0
543
543
544 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
544 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
545 runargs=None, appendpid=False):
545 runargs=None, appendpid=False):
546 '''Run a command as a service.'''
546 '''Run a command as a service.'''
547
547
548 if opts['daemon'] and not opts['daemon_pipefds']:
548 if opts['daemon'] and not opts['daemon_pipefds']:
549 # Signal child process startup with file removal
549 # Signal child process startup with file removal
550 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
550 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
551 os.close(lockfd)
551 os.close(lockfd)
552 try:
552 try:
553 if not runargs:
553 if not runargs:
554 runargs = util.hgcmd() + sys.argv[1:]
554 runargs = util.hgcmd() + sys.argv[1:]
555 runargs.append('--daemon-pipefds=%s' % lockpath)
555 runargs.append('--daemon-pipefds=%s' % lockpath)
556 # Don't pass --cwd to the child process, because we've already
556 # Don't pass --cwd to the child process, because we've already
557 # changed directory.
557 # changed directory.
558 for i in xrange(1, len(runargs)):
558 for i in xrange(1, len(runargs)):
559 if runargs[i].startswith('--cwd='):
559 if runargs[i].startswith('--cwd='):
560 del runargs[i]
560 del runargs[i]
561 break
561 break
562 elif runargs[i].startswith('--cwd'):
562 elif runargs[i].startswith('--cwd'):
563 del runargs[i:i + 2]
563 del runargs[i:i + 2]
564 break
564 break
565 def condfn():
565 def condfn():
566 return not os.path.exists(lockpath)
566 return not os.path.exists(lockpath)
567 pid = util.rundetached(runargs, condfn)
567 pid = util.rundetached(runargs, condfn)
568 if pid < 0:
568 if pid < 0:
569 raise util.Abort(_('child process failed to start'))
569 raise util.Abort(_('child process failed to start'))
570 finally:
570 finally:
571 try:
571 try:
572 os.unlink(lockpath)
572 os.unlink(lockpath)
573 except OSError, e:
573 except OSError, e:
574 if e.errno != errno.ENOENT:
574 if e.errno != errno.ENOENT:
575 raise
575 raise
576 if parentfn:
576 if parentfn:
577 return parentfn(pid)
577 return parentfn(pid)
578 else:
578 else:
579 return
579 return
580
580
581 if initfn:
581 if initfn:
582 initfn()
582 initfn()
583
583
584 if opts['pid_file']:
584 if opts['pid_file']:
585 mode = appendpid and 'a' or 'w'
585 mode = appendpid and 'a' or 'w'
586 fp = open(opts['pid_file'], mode)
586 fp = open(opts['pid_file'], mode)
587 fp.write(str(os.getpid()) + '\n')
587 fp.write(str(os.getpid()) + '\n')
588 fp.close()
588 fp.close()
589
589
590 if opts['daemon_pipefds']:
590 if opts['daemon_pipefds']:
591 lockpath = opts['daemon_pipefds']
591 lockpath = opts['daemon_pipefds']
592 try:
592 try:
593 os.setsid()
593 os.setsid()
594 except AttributeError:
594 except AttributeError:
595 pass
595 pass
596 os.unlink(lockpath)
596 os.unlink(lockpath)
597 util.hidewindow()
597 util.hidewindow()
598 sys.stdout.flush()
598 sys.stdout.flush()
599 sys.stderr.flush()
599 sys.stderr.flush()
600
600
601 nullfd = os.open(util.nulldev, os.O_RDWR)
601 nullfd = os.open(util.nulldev, os.O_RDWR)
602 logfilefd = nullfd
602 logfilefd = nullfd
603 if logfile:
603 if logfile:
604 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
604 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
605 os.dup2(nullfd, 0)
605 os.dup2(nullfd, 0)
606 os.dup2(logfilefd, 1)
606 os.dup2(logfilefd, 1)
607 os.dup2(logfilefd, 2)
607 os.dup2(logfilefd, 2)
608 if nullfd not in (0, 1, 2):
608 if nullfd not in (0, 1, 2):
609 os.close(nullfd)
609 os.close(nullfd)
610 if logfile and logfilefd not in (0, 1, 2):
610 if logfile and logfilefd not in (0, 1, 2):
611 os.close(logfilefd)
611 os.close(logfilefd)
612
612
613 if runfn:
613 if runfn:
614 return runfn()
614 return runfn()
615
615
616 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
616 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
617 opts=None):
617 opts=None):
618 '''export changesets as hg patches.'''
618 '''export changesets as hg patches.'''
619
619
620 total = len(revs)
620 total = len(revs)
621 revwidth = max([len(str(rev)) for rev in revs])
621 revwidth = max([len(str(rev)) for rev in revs])
622
622
623 def single(rev, seqno, fp):
623 def single(rev, seqno, fp):
624 ctx = repo[rev]
624 ctx = repo[rev]
625 node = ctx.node()
625 node = ctx.node()
626 parents = [p.node() for p in ctx.parents() if p]
626 parents = [p.node() for p in ctx.parents() if p]
627 branch = ctx.branch()
627 branch = ctx.branch()
628 if switch_parent:
628 if switch_parent:
629 parents.reverse()
629 parents.reverse()
630 prev = (parents and parents[0]) or nullid
630 prev = (parents and parents[0]) or nullid
631
631
632 if not fp:
632 if not fp:
633 fp = make_file(repo, template, node, total=total, seqno=seqno,
633 fp = make_file(repo, template, node, total=total, seqno=seqno,
634 revwidth=revwidth, mode='ab')
634 revwidth=revwidth, mode='ab')
635 if fp != sys.stdout and hasattr(fp, 'name'):
635 if fp != sys.stdout and hasattr(fp, 'name'):
636 repo.ui.note("%s\n" % fp.name)
636 repo.ui.note("%s\n" % fp.name)
637
637
638 fp.write("# HG changeset patch\n")
638 fp.write("# HG changeset patch\n")
639 fp.write("# User %s\n" % ctx.user())
639 fp.write("# User %s\n" % ctx.user())
640 fp.write("# Date %d %d\n" % ctx.date())
640 fp.write("# Date %d %d\n" % ctx.date())
641 if branch and (branch != 'default'):
641 if branch and (branch != 'default'):
642 fp.write("# Branch %s\n" % branch)
642 fp.write("# Branch %s\n" % branch)
643 fp.write("# Node ID %s\n" % hex(node))
643 fp.write("# Node ID %s\n" % hex(node))
644 fp.write("# Parent %s\n" % hex(prev))
644 fp.write("# Parent %s\n" % hex(prev))
645 if len(parents) > 1:
645 if len(parents) > 1:
646 fp.write("# Parent %s\n" % hex(parents[1]))
646 fp.write("# Parent %s\n" % hex(parents[1]))
647 fp.write(ctx.description().rstrip())
647 fp.write(ctx.description().rstrip())
648 fp.write("\n\n")
648 fp.write("\n\n")
649
649
650 for chunk in patch.diff(repo, prev, node, opts=opts):
650 for chunk in patch.diff(repo, prev, node, opts=opts):
651 fp.write(chunk)
651 fp.write(chunk)
652
652
653 for seqno, rev in enumerate(revs):
653 for seqno, rev in enumerate(revs):
654 single(rev, seqno + 1, fp)
654 single(rev, seqno + 1, fp)
655
655
656 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
656 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
657 changes=None, stat=False, fp=None):
657 changes=None, stat=False, fp=None):
658 '''show diff or diffstat.'''
658 '''show diff or diffstat.'''
659 if fp is None:
659 if fp is None:
660 write = ui.write
660 write = ui.write
661 else:
661 else:
662 def write(s, **kw):
662 def write(s, **kw):
663 fp.write(s)
663 fp.write(s)
664
664
665 if stat:
665 if stat:
666 diffopts.context = 0
666 diffopts.context = 0
667 width = 80
667 width = 80
668 if not ui.plain():
668 if not ui.plain():
669 width = util.termwidth()
669 width = util.termwidth()
670 chunks = patch.diff(repo, node1, node2, match, changes, diffopts)
670 chunks = patch.diff(repo, node1, node2, match, changes, diffopts)
671 for chunk, label in patch.diffstatui(util.iterlines(chunks),
671 for chunk, label in patch.diffstatui(util.iterlines(chunks),
672 width=width,
672 width=width,
673 git=diffopts.git):
673 git=diffopts.git):
674 write(chunk, label=label)
674 write(chunk, label=label)
675 else:
675 else:
676 for chunk, label in patch.diffui(repo, node1, node2, match,
676 for chunk, label in patch.diffui(repo, node1, node2, match,
677 changes, diffopts):
677 changes, diffopts):
678 write(chunk, label=label)
678 write(chunk, label=label)
679
679
680 class changeset_printer(object):
680 class changeset_printer(object):
681 '''show changeset information when templating not requested.'''
681 '''show changeset information when templating not requested.'''
682
682
683 def __init__(self, ui, repo, patch, diffopts, buffered):
683 def __init__(self, ui, repo, patch, diffopts, buffered):
684 self.ui = ui
684 self.ui = ui
685 self.repo = repo
685 self.repo = repo
686 self.buffered = buffered
686 self.buffered = buffered
687 self.patch = patch
687 self.patch = patch
688 self.diffopts = diffopts
688 self.diffopts = diffopts
689 self.header = {}
689 self.header = {}
690 self.doneheader = False
691 self.hunk = {}
690 self.hunk = {}
692 self.lastheader = None
691 self.lastheader = None
693 self.footer = None
692 self.footer = None
694
693
695 def flush(self, rev):
694 def flush(self, rev):
696 if rev in self.header:
695 if rev in self.header:
697 h = self.header[rev]
696 h = self.header[rev]
698 if h != self.lastheader:
697 if h != self.lastheader:
699 self.lastheader = h
698 self.lastheader = h
700 self.ui.write(h)
699 self.ui.write(h)
701 del self.header[rev]
700 del self.header[rev]
702 if rev in self.hunk:
701 if rev in self.hunk:
703 self.ui.write(self.hunk[rev])
702 self.ui.write(self.hunk[rev])
704 del self.hunk[rev]
703 del self.hunk[rev]
705 return 1
704 return 1
706 return 0
705 return 0
707
706
708 def close(self):
707 def close(self):
709 if self.footer:
708 if self.footer:
710 self.ui.write(self.footer)
709 self.ui.write(self.footer)
711
710
712 def show(self, ctx, copies=None, **props):
711 def show(self, ctx, copies=None, **props):
713 if self.buffered:
712 if self.buffered:
714 self.ui.pushbuffer()
713 self.ui.pushbuffer()
715 self._show(ctx, copies, props)
714 self._show(ctx, copies, props)
716 self.hunk[ctx.rev()] = self.ui.popbuffer(labeled=True)
715 self.hunk[ctx.rev()] = self.ui.popbuffer(labeled=True)
717 else:
716 else:
718 self._show(ctx, copies, props)
717 self._show(ctx, copies, props)
719
718
720 def _show(self, ctx, copies, props):
719 def _show(self, ctx, copies, props):
721 '''show a single changeset or file revision'''
720 '''show a single changeset or file revision'''
722 changenode = ctx.node()
721 changenode = ctx.node()
723 rev = ctx.rev()
722 rev = ctx.rev()
724
723
725 if self.ui.quiet:
724 if self.ui.quiet:
726 self.ui.write("%d:%s\n" % (rev, short(changenode)),
725 self.ui.write("%d:%s\n" % (rev, short(changenode)),
727 label='log.node')
726 label='log.node')
728 return
727 return
729
728
730 log = self.repo.changelog
729 log = self.repo.changelog
731 date = util.datestr(ctx.date())
730 date = util.datestr(ctx.date())
732
731
733 hexfunc = self.ui.debugflag and hex or short
732 hexfunc = self.ui.debugflag and hex or short
734
733
735 parents = [(p, hexfunc(log.node(p)))
734 parents = [(p, hexfunc(log.node(p)))
736 for p in self._meaningful_parentrevs(log, rev)]
735 for p in self._meaningful_parentrevs(log, rev)]
737
736
738 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)),
737 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)),
739 label='log.changeset')
738 label='log.changeset')
740
739
741 branch = ctx.branch()
740 branch = ctx.branch()
742 # don't show the default branch name
741 # don't show the default branch name
743 if branch != 'default':
742 if branch != 'default':
744 branch = encoding.tolocal(branch)
743 branch = encoding.tolocal(branch)
745 self.ui.write(_("branch: %s\n") % branch,
744 self.ui.write(_("branch: %s\n") % branch,
746 label='log.branch')
745 label='log.branch')
747 for tag in self.repo.nodetags(changenode):
746 for tag in self.repo.nodetags(changenode):
748 self.ui.write(_("tag: %s\n") % tag,
747 self.ui.write(_("tag: %s\n") % tag,
749 label='log.tag')
748 label='log.tag')
750 for parent in parents:
749 for parent in parents:
751 self.ui.write(_("parent: %d:%s\n") % parent,
750 self.ui.write(_("parent: %d:%s\n") % parent,
752 label='log.parent')
751 label='log.parent')
753
752
754 if self.ui.debugflag:
753 if self.ui.debugflag:
755 mnode = ctx.manifestnode()
754 mnode = ctx.manifestnode()
756 self.ui.write(_("manifest: %d:%s\n") %
755 self.ui.write(_("manifest: %d:%s\n") %
757 (self.repo.manifest.rev(mnode), hex(mnode)),
756 (self.repo.manifest.rev(mnode), hex(mnode)),
758 label='ui.debug log.manifest')
757 label='ui.debug log.manifest')
759 self.ui.write(_("user: %s\n") % ctx.user(),
758 self.ui.write(_("user: %s\n") % ctx.user(),
760 label='log.user')
759 label='log.user')
761 self.ui.write(_("date: %s\n") % date,
760 self.ui.write(_("date: %s\n") % date,
762 label='log.date')
761 label='log.date')
763
762
764 if self.ui.debugflag:
763 if self.ui.debugflag:
765 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
764 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
766 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
765 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
767 files):
766 files):
768 if value:
767 if value:
769 self.ui.write("%-12s %s\n" % (key, " ".join(value)),
768 self.ui.write("%-12s %s\n" % (key, " ".join(value)),
770 label='ui.debug log.files')
769 label='ui.debug log.files')
771 elif ctx.files() and self.ui.verbose:
770 elif ctx.files() and self.ui.verbose:
772 self.ui.write(_("files: %s\n") % " ".join(ctx.files()),
771 self.ui.write(_("files: %s\n") % " ".join(ctx.files()),
773 label='ui.note log.files')
772 label='ui.note log.files')
774 if copies and self.ui.verbose:
773 if copies and self.ui.verbose:
775 copies = ['%s (%s)' % c for c in copies]
774 copies = ['%s (%s)' % c for c in copies]
776 self.ui.write(_("copies: %s\n") % ' '.join(copies),
775 self.ui.write(_("copies: %s\n") % ' '.join(copies),
777 label='ui.note log.copies')
776 label='ui.note log.copies')
778
777
779 extra = ctx.extra()
778 extra = ctx.extra()
780 if extra and self.ui.debugflag:
779 if extra and self.ui.debugflag:
781 for key, value in sorted(extra.items()):
780 for key, value in sorted(extra.items()):
782 self.ui.write(_("extra: %s=%s\n")
781 self.ui.write(_("extra: %s=%s\n")
783 % (key, value.encode('string_escape')),
782 % (key, value.encode('string_escape')),
784 label='ui.debug log.extra')
783 label='ui.debug log.extra')
785
784
786 description = ctx.description().strip()
785 description = ctx.description().strip()
787 if description:
786 if description:
788 if self.ui.verbose:
787 if self.ui.verbose:
789 self.ui.write(_("description:\n"),
788 self.ui.write(_("description:\n"),
790 label='ui.note log.description')
789 label='ui.note log.description')
791 self.ui.write(description,
790 self.ui.write(description,
792 label='ui.note log.description')
791 label='ui.note log.description')
793 self.ui.write("\n\n")
792 self.ui.write("\n\n")
794 else:
793 else:
795 self.ui.write(_("summary: %s\n") %
794 self.ui.write(_("summary: %s\n") %
796 description.splitlines()[0],
795 description.splitlines()[0],
797 label='log.summary')
796 label='log.summary')
798 self.ui.write("\n")
797 self.ui.write("\n")
799
798
800 self.showpatch(changenode)
799 self.showpatch(changenode)
801
800
802 def showpatch(self, node):
801 def showpatch(self, node):
803 if self.patch:
802 if self.patch:
804 stat = self.diffopts.get('stat')
803 stat = self.diffopts.get('stat')
805 diffopts = patch.diffopts(self.ui, self.diffopts)
804 diffopts = patch.diffopts(self.ui, self.diffopts)
806 prev = self.repo.changelog.parents(node)[0]
805 prev = self.repo.changelog.parents(node)[0]
807 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
806 diffordiffstat(self.ui, self.repo, diffopts, prev, node,
808 match=self.patch, stat=stat)
807 match=self.patch, stat=stat)
809 self.ui.write("\n")
808 self.ui.write("\n")
810
809
811 def _meaningful_parentrevs(self, log, rev):
810 def _meaningful_parentrevs(self, log, rev):
812 """Return list of meaningful (or all if debug) parentrevs for rev.
811 """Return list of meaningful (or all if debug) parentrevs for rev.
813
812
814 For merges (two non-nullrev revisions) both parents are meaningful.
813 For merges (two non-nullrev revisions) both parents are meaningful.
815 Otherwise the first parent revision is considered meaningful if it
814 Otherwise the first parent revision is considered meaningful if it
816 is not the preceding revision.
815 is not the preceding revision.
817 """
816 """
818 parents = log.parentrevs(rev)
817 parents = log.parentrevs(rev)
819 if not self.ui.debugflag and parents[1] == nullrev:
818 if not self.ui.debugflag and parents[1] == nullrev:
820 if parents[0] >= rev - 1:
819 if parents[0] >= rev - 1:
821 parents = []
820 parents = []
822 else:
821 else:
823 parents = [parents[0]]
822 parents = [parents[0]]
824 return parents
823 return parents
825
824
826
825
827 class changeset_templater(changeset_printer):
826 class changeset_templater(changeset_printer):
828 '''format changeset information.'''
827 '''format changeset information.'''
829
828
830 def __init__(self, ui, repo, patch, diffopts, mapfile, buffered):
829 def __init__(self, ui, repo, patch, diffopts, mapfile, buffered):
831 changeset_printer.__init__(self, ui, repo, patch, diffopts, buffered)
830 changeset_printer.__init__(self, ui, repo, patch, diffopts, buffered)
832 formatnode = ui.debugflag and (lambda x: x) or (lambda x: x[:12])
831 formatnode = ui.debugflag and (lambda x: x) or (lambda x: x[:12])
833 defaulttempl = {
832 defaulttempl = {
834 'parent': '{rev}:{node|formatnode} ',
833 'parent': '{rev}:{node|formatnode} ',
835 'manifest': '{rev}:{node|formatnode}',
834 'manifest': '{rev}:{node|formatnode}',
836 'file_copy': '{name} ({source})',
835 'file_copy': '{name} ({source})',
837 'extra': '{key}={value|stringescape}'
836 'extra': '{key}={value|stringescape}'
838 }
837 }
839 # filecopy is preserved for compatibility reasons
838 # filecopy is preserved for compatibility reasons
840 defaulttempl['filecopy'] = defaulttempl['file_copy']
839 defaulttempl['filecopy'] = defaulttempl['file_copy']
841 self.t = templater.templater(mapfile, {'formatnode': formatnode},
840 self.t = templater.templater(mapfile, {'formatnode': formatnode},
842 cache=defaulttempl)
841 cache=defaulttempl)
843 self.cache = {}
842 self.cache = {}
844
843
845 def use_template(self, t):
844 def use_template(self, t):
846 '''set template string to use'''
845 '''set template string to use'''
847 self.t.cache['changeset'] = t
846 self.t.cache['changeset'] = t
848
847
849 def _meaningful_parentrevs(self, ctx):
848 def _meaningful_parentrevs(self, ctx):
850 """Return list of meaningful (or all if debug) parentrevs for rev.
849 """Return list of meaningful (or all if debug) parentrevs for rev.
851 """
850 """
852 parents = ctx.parents()
851 parents = ctx.parents()
853 if len(parents) > 1:
852 if len(parents) > 1:
854 return parents
853 return parents
855 if self.ui.debugflag:
854 if self.ui.debugflag:
856 return [parents[0], self.repo['null']]
855 return [parents[0], self.repo['null']]
857 if parents[0].rev() >= ctx.rev() - 1:
856 if parents[0].rev() >= ctx.rev() - 1:
858 return []
857 return []
859 return parents
858 return parents
860
859
861 def _show(self, ctx, copies, props):
860 def _show(self, ctx, copies, props):
862 '''show a single changeset or file revision'''
861 '''show a single changeset or file revision'''
863
862
864 showlist = templatekw.showlist
863 showlist = templatekw.showlist
865
864
866 # showparents() behaviour depends on ui trace level which
865 # showparents() behaviour depends on ui trace level which
867 # causes unexpected behaviours at templating level and makes
866 # causes unexpected behaviours at templating level and makes
868 # it harder to extract it in a standalone function. Its
867 # it harder to extract it in a standalone function. Its
869 # behaviour cannot be changed so leave it here for now.
868 # behaviour cannot be changed so leave it here for now.
870 def showparents(**args):
869 def showparents(**args):
871 ctx = args['ctx']
870 ctx = args['ctx']
872 parents = [[('rev', p.rev()), ('node', p.hex())]
871 parents = [[('rev', p.rev()), ('node', p.hex())]
873 for p in self._meaningful_parentrevs(ctx)]
872 for p in self._meaningful_parentrevs(ctx)]
874 return showlist('parent', parents, **args)
873 return showlist('parent', parents, **args)
875
874
876 props = props.copy()
875 props = props.copy()
877 props.update(templatekw.keywords)
876 props.update(templatekw.keywords)
878 props['parents'] = showparents
877 props['parents'] = showparents
879 props['templ'] = self.t
878 props['templ'] = self.t
880 props['ctx'] = ctx
879 props['ctx'] = ctx
881 props['repo'] = self.repo
880 props['repo'] = self.repo
882 props['revcache'] = {'copies': copies}
881 props['revcache'] = {'copies': copies}
883 props['cache'] = self.cache
882 props['cache'] = self.cache
884
883
885 # find correct templates for current mode
884 # find correct templates for current mode
886
885
887 tmplmodes = [
886 tmplmodes = [
888 (True, None),
887 (True, None),
889 (self.ui.verbose, 'verbose'),
888 (self.ui.verbose, 'verbose'),
890 (self.ui.quiet, 'quiet'),
889 (self.ui.quiet, 'quiet'),
891 (self.ui.debugflag, 'debug'),
890 (self.ui.debugflag, 'debug'),
892 ]
891 ]
893
892
894 types = {'header': '', 'footer':'', 'changeset': 'changeset'}
893 types = {'header': '', 'footer':'', 'changeset': 'changeset'}
895 for mode, postfix in tmplmodes:
894 for mode, postfix in tmplmodes:
896 for type in types:
895 for type in types:
897 cur = postfix and ('%s_%s' % (type, postfix)) or type
896 cur = postfix and ('%s_%s' % (type, postfix)) or type
898 if mode and cur in self.t:
897 if mode and cur in self.t:
899 types[type] = cur
898 types[type] = cur
900
899
901 try:
900 try:
902
901
903 # write header
902 # write header
904 if types['header']:
903 if types['header']:
905 h = templater.stringify(self.t(types['header'], **props))
904 h = templater.stringify(self.t(types['header'], **props))
906 if self.buffered:
905 if self.buffered:
907 self.header[ctx.rev()] = h
906 self.header[ctx.rev()] = h
908 else:
907 else:
909 if not self.doneheader:
908 if self.lastheader != h:
909 self.lastheader = h
910 self.ui.write(h)
910 self.ui.write(h)
911 self.doneheader = True
912
911
913 # write changeset metadata, then patch if requested
912 # write changeset metadata, then patch if requested
914 key = types['changeset']
913 key = types['changeset']
915 self.ui.write(templater.stringify(self.t(key, **props)))
914 self.ui.write(templater.stringify(self.t(key, **props)))
916 self.showpatch(ctx.node())
915 self.showpatch(ctx.node())
917
916
918 if types['footer']:
917 if types['footer']:
919 if not self.footer:
918 if not self.footer:
920 self.footer = templater.stringify(self.t(types['footer'],
919 self.footer = templater.stringify(self.t(types['footer'],
921 **props))
920 **props))
922
921
923 except KeyError, inst:
922 except KeyError, inst:
924 msg = _("%s: no key named '%s'")
923 msg = _("%s: no key named '%s'")
925 raise util.Abort(msg % (self.t.mapfile, inst.args[0]))
924 raise util.Abort(msg % (self.t.mapfile, inst.args[0]))
926 except SyntaxError, inst:
925 except SyntaxError, inst:
927 raise util.Abort('%s: %s' % (self.t.mapfile, inst.args[0]))
926 raise util.Abort('%s: %s' % (self.t.mapfile, inst.args[0]))
928
927
929 def show_changeset(ui, repo, opts, buffered=False, matchfn=False):
928 def show_changeset(ui, repo, opts, buffered=False, matchfn=False):
930 """show one changeset using template or regular display.
929 """show one changeset using template or regular display.
931
930
932 Display format will be the first non-empty hit of:
931 Display format will be the first non-empty hit of:
933 1. option 'template'
932 1. option 'template'
934 2. option 'style'
933 2. option 'style'
935 3. [ui] setting 'logtemplate'
934 3. [ui] setting 'logtemplate'
936 4. [ui] setting 'style'
935 4. [ui] setting 'style'
937 If all of these values are either the unset or the empty string,
936 If all of these values are either the unset or the empty string,
938 regular display via changeset_printer() is done.
937 regular display via changeset_printer() is done.
939 """
938 """
940 # options
939 # options
941 patch = False
940 patch = False
942 if opts.get('patch') or opts.get('stat'):
941 if opts.get('patch') or opts.get('stat'):
943 patch = matchfn or matchall(repo)
942 patch = matchfn or matchall(repo)
944
943
945 tmpl = opts.get('template')
944 tmpl = opts.get('template')
946 style = None
945 style = None
947 if tmpl:
946 if tmpl:
948 tmpl = templater.parsestring(tmpl, quoted=False)
947 tmpl = templater.parsestring(tmpl, quoted=False)
949 else:
948 else:
950 style = opts.get('style')
949 style = opts.get('style')
951
950
952 # ui settings
951 # ui settings
953 if not (tmpl or style):
952 if not (tmpl or style):
954 tmpl = ui.config('ui', 'logtemplate')
953 tmpl = ui.config('ui', 'logtemplate')
955 if tmpl:
954 if tmpl:
956 tmpl = templater.parsestring(tmpl)
955 tmpl = templater.parsestring(tmpl)
957 else:
956 else:
958 style = util.expandpath(ui.config('ui', 'style', ''))
957 style = util.expandpath(ui.config('ui', 'style', ''))
959
958
960 if not (tmpl or style):
959 if not (tmpl or style):
961 return changeset_printer(ui, repo, patch, opts, buffered)
960 return changeset_printer(ui, repo, patch, opts, buffered)
962
961
963 mapfile = None
962 mapfile = None
964 if style and not tmpl:
963 if style and not tmpl:
965 mapfile = style
964 mapfile = style
966 if not os.path.split(mapfile)[0]:
965 if not os.path.split(mapfile)[0]:
967 mapname = (templater.templatepath('map-cmdline.' + mapfile)
966 mapname = (templater.templatepath('map-cmdline.' + mapfile)
968 or templater.templatepath(mapfile))
967 or templater.templatepath(mapfile))
969 if mapname:
968 if mapname:
970 mapfile = mapname
969 mapfile = mapname
971
970
972 try:
971 try:
973 t = changeset_templater(ui, repo, patch, opts, mapfile, buffered)
972 t = changeset_templater(ui, repo, patch, opts, mapfile, buffered)
974 except SyntaxError, inst:
973 except SyntaxError, inst:
975 raise util.Abort(inst.args[0])
974 raise util.Abort(inst.args[0])
976 if tmpl:
975 if tmpl:
977 t.use_template(tmpl)
976 t.use_template(tmpl)
978 return t
977 return t
979
978
980 def finddate(ui, repo, date):
979 def finddate(ui, repo, date):
981 """Find the tipmost changeset that matches the given date spec"""
980 """Find the tipmost changeset that matches the given date spec"""
982
981
983 df = util.matchdate(date)
982 df = util.matchdate(date)
984 m = matchall(repo)
983 m = matchall(repo)
985 results = {}
984 results = {}
986
985
987 def prep(ctx, fns):
986 def prep(ctx, fns):
988 d = ctx.date()
987 d = ctx.date()
989 if df(d[0]):
988 if df(d[0]):
990 results[ctx.rev()] = d
989 results[ctx.rev()] = d
991
990
992 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
991 for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
993 rev = ctx.rev()
992 rev = ctx.rev()
994 if rev in results:
993 if rev in results:
995 ui.status(_("Found revision %s from %s\n") %
994 ui.status(_("Found revision %s from %s\n") %
996 (rev, util.datestr(results[rev])))
995 (rev, util.datestr(results[rev])))
997 return str(rev)
996 return str(rev)
998
997
999 raise util.Abort(_("revision matching date not found"))
998 raise util.Abort(_("revision matching date not found"))
1000
999
1001 def walkchangerevs(repo, match, opts, prepare):
1000 def walkchangerevs(repo, match, opts, prepare):
1002 '''Iterate over files and the revs in which they changed.
1001 '''Iterate over files and the revs in which they changed.
1003
1002
1004 Callers most commonly need to iterate backwards over the history
1003 Callers most commonly need to iterate backwards over the history
1005 in which they are interested. Doing so has awful (quadratic-looking)
1004 in which they are interested. Doing so has awful (quadratic-looking)
1006 performance, so we use iterators in a "windowed" way.
1005 performance, so we use iterators in a "windowed" way.
1007
1006
1008 We walk a window of revisions in the desired order. Within the
1007 We walk a window of revisions in the desired order. Within the
1009 window, we first walk forwards to gather data, then in the desired
1008 window, we first walk forwards to gather data, then in the desired
1010 order (usually backwards) to display it.
1009 order (usually backwards) to display it.
1011
1010
1012 This function returns an iterator yielding contexts. Before
1011 This function returns an iterator yielding contexts. Before
1013 yielding each context, the iterator will first call the prepare
1012 yielding each context, the iterator will first call the prepare
1014 function on each context in the window in forward order.'''
1013 function on each context in the window in forward order.'''
1015
1014
1016 def increasing_windows(start, end, windowsize=8, sizelimit=512):
1015 def increasing_windows(start, end, windowsize=8, sizelimit=512):
1017 if start < end:
1016 if start < end:
1018 while start < end:
1017 while start < end:
1019 yield start, min(windowsize, end - start)
1018 yield start, min(windowsize, end - start)
1020 start += windowsize
1019 start += windowsize
1021 if windowsize < sizelimit:
1020 if windowsize < sizelimit:
1022 windowsize *= 2
1021 windowsize *= 2
1023 else:
1022 else:
1024 while start > end:
1023 while start > end:
1025 yield start, min(windowsize, start - end - 1)
1024 yield start, min(windowsize, start - end - 1)
1026 start -= windowsize
1025 start -= windowsize
1027 if windowsize < sizelimit:
1026 if windowsize < sizelimit:
1028 windowsize *= 2
1027 windowsize *= 2
1029
1028
1030 follow = opts.get('follow') or opts.get('follow_first')
1029 follow = opts.get('follow') or opts.get('follow_first')
1031
1030
1032 if not len(repo):
1031 if not len(repo):
1033 return []
1032 return []
1034
1033
1035 if follow:
1034 if follow:
1036 defrange = '%s:0' % repo['.'].rev()
1035 defrange = '%s:0' % repo['.'].rev()
1037 else:
1036 else:
1038 defrange = '-1:0'
1037 defrange = '-1:0'
1039 revs = revrange(repo, opts['rev'] or [defrange])
1038 revs = revrange(repo, opts['rev'] or [defrange])
1040 if not revs:
1039 if not revs:
1041 return []
1040 return []
1042 wanted = set()
1041 wanted = set()
1043 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1042 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1044 fncache = {}
1043 fncache = {}
1045 change = util.cachefunc(repo.changectx)
1044 change = util.cachefunc(repo.changectx)
1046
1045
1047 if not slowpath and not match.files():
1046 if not slowpath and not match.files():
1048 # No files, no patterns. Display all revs.
1047 # No files, no patterns. Display all revs.
1049 wanted = set(revs)
1048 wanted = set(revs)
1050 copies = []
1049 copies = []
1051
1050
1052 if not slowpath:
1051 if not slowpath:
1053 # Only files, no patterns. Check the history of each file.
1052 # Only files, no patterns. Check the history of each file.
1054 def filerevgen(filelog, node):
1053 def filerevgen(filelog, node):
1055 cl_count = len(repo)
1054 cl_count = len(repo)
1056 if node is None:
1055 if node is None:
1057 last = len(filelog) - 1
1056 last = len(filelog) - 1
1058 else:
1057 else:
1059 last = filelog.rev(node)
1058 last = filelog.rev(node)
1060 for i, window in increasing_windows(last, nullrev):
1059 for i, window in increasing_windows(last, nullrev):
1061 revs = []
1060 revs = []
1062 for j in xrange(i - window, i + 1):
1061 for j in xrange(i - window, i + 1):
1063 n = filelog.node(j)
1062 n = filelog.node(j)
1064 revs.append((filelog.linkrev(j),
1063 revs.append((filelog.linkrev(j),
1065 follow and filelog.renamed(n)))
1064 follow and filelog.renamed(n)))
1066 for rev in reversed(revs):
1065 for rev in reversed(revs):
1067 # only yield rev for which we have the changelog, it can
1066 # only yield rev for which we have the changelog, it can
1068 # happen while doing "hg log" during a pull or commit
1067 # happen while doing "hg log" during a pull or commit
1069 if rev[0] < cl_count:
1068 if rev[0] < cl_count:
1070 yield rev
1069 yield rev
1071 def iterfiles():
1070 def iterfiles():
1072 for filename in match.files():
1071 for filename in match.files():
1073 yield filename, None
1072 yield filename, None
1074 for filename_node in copies:
1073 for filename_node in copies:
1075 yield filename_node
1074 yield filename_node
1076 minrev, maxrev = min(revs), max(revs)
1075 minrev, maxrev = min(revs), max(revs)
1077 for file_, node in iterfiles():
1076 for file_, node in iterfiles():
1078 filelog = repo.file(file_)
1077 filelog = repo.file(file_)
1079 if not len(filelog):
1078 if not len(filelog):
1080 if node is None:
1079 if node is None:
1081 # A zero count may be a directory or deleted file, so
1080 # A zero count may be a directory or deleted file, so
1082 # try to find matching entries on the slow path.
1081 # try to find matching entries on the slow path.
1083 if follow:
1082 if follow:
1084 raise util.Abort(
1083 raise util.Abort(
1085 _('cannot follow nonexistent file: "%s"') % file_)
1084 _('cannot follow nonexistent file: "%s"') % file_)
1086 slowpath = True
1085 slowpath = True
1087 break
1086 break
1088 else:
1087 else:
1089 continue
1088 continue
1090 for rev, copied in filerevgen(filelog, node):
1089 for rev, copied in filerevgen(filelog, node):
1091 if rev <= maxrev:
1090 if rev <= maxrev:
1092 if rev < minrev:
1091 if rev < minrev:
1093 break
1092 break
1094 fncache.setdefault(rev, [])
1093 fncache.setdefault(rev, [])
1095 fncache[rev].append(file_)
1094 fncache[rev].append(file_)
1096 wanted.add(rev)
1095 wanted.add(rev)
1097 if copied:
1096 if copied:
1098 copies.append(copied)
1097 copies.append(copied)
1099 if slowpath:
1098 if slowpath:
1100 if follow:
1099 if follow:
1101 raise util.Abort(_('can only follow copies/renames for explicit '
1100 raise util.Abort(_('can only follow copies/renames for explicit '
1102 'filenames'))
1101 'filenames'))
1103
1102
1104 # The slow path checks files modified in every changeset.
1103 # The slow path checks files modified in every changeset.
1105 def changerevgen():
1104 def changerevgen():
1106 for i, window in increasing_windows(len(repo) - 1, nullrev):
1105 for i, window in increasing_windows(len(repo) - 1, nullrev):
1107 for j in xrange(i - window, i + 1):
1106 for j in xrange(i - window, i + 1):
1108 yield change(j)
1107 yield change(j)
1109
1108
1110 for ctx in changerevgen():
1109 for ctx in changerevgen():
1111 matches = filter(match, ctx.files())
1110 matches = filter(match, ctx.files())
1112 if matches:
1111 if matches:
1113 fncache[ctx.rev()] = matches
1112 fncache[ctx.rev()] = matches
1114 wanted.add(ctx.rev())
1113 wanted.add(ctx.rev())
1115
1114
1116 class followfilter(object):
1115 class followfilter(object):
1117 def __init__(self, onlyfirst=False):
1116 def __init__(self, onlyfirst=False):
1118 self.startrev = nullrev
1117 self.startrev = nullrev
1119 self.roots = set()
1118 self.roots = set()
1120 self.onlyfirst = onlyfirst
1119 self.onlyfirst = onlyfirst
1121
1120
1122 def match(self, rev):
1121 def match(self, rev):
1123 def realparents(rev):
1122 def realparents(rev):
1124 if self.onlyfirst:
1123 if self.onlyfirst:
1125 return repo.changelog.parentrevs(rev)[0:1]
1124 return repo.changelog.parentrevs(rev)[0:1]
1126 else:
1125 else:
1127 return filter(lambda x: x != nullrev,
1126 return filter(lambda x: x != nullrev,
1128 repo.changelog.parentrevs(rev))
1127 repo.changelog.parentrevs(rev))
1129
1128
1130 if self.startrev == nullrev:
1129 if self.startrev == nullrev:
1131 self.startrev = rev
1130 self.startrev = rev
1132 return True
1131 return True
1133
1132
1134 if rev > self.startrev:
1133 if rev > self.startrev:
1135 # forward: all descendants
1134 # forward: all descendants
1136 if not self.roots:
1135 if not self.roots:
1137 self.roots.add(self.startrev)
1136 self.roots.add(self.startrev)
1138 for parent in realparents(rev):
1137 for parent in realparents(rev):
1139 if parent in self.roots:
1138 if parent in self.roots:
1140 self.roots.add(rev)
1139 self.roots.add(rev)
1141 return True
1140 return True
1142 else:
1141 else:
1143 # backwards: all parents
1142 # backwards: all parents
1144 if not self.roots:
1143 if not self.roots:
1145 self.roots.update(realparents(self.startrev))
1144 self.roots.update(realparents(self.startrev))
1146 if rev in self.roots:
1145 if rev in self.roots:
1147 self.roots.remove(rev)
1146 self.roots.remove(rev)
1148 self.roots.update(realparents(rev))
1147 self.roots.update(realparents(rev))
1149 return True
1148 return True
1150
1149
1151 return False
1150 return False
1152
1151
1153 # it might be worthwhile to do this in the iterator if the rev range
1152 # it might be worthwhile to do this in the iterator if the rev range
1154 # is descending and the prune args are all within that range
1153 # is descending and the prune args are all within that range
1155 for rev in opts.get('prune', ()):
1154 for rev in opts.get('prune', ()):
1156 rev = repo.changelog.rev(repo.lookup(rev))
1155 rev = repo.changelog.rev(repo.lookup(rev))
1157 ff = followfilter()
1156 ff = followfilter()
1158 stop = min(revs[0], revs[-1])
1157 stop = min(revs[0], revs[-1])
1159 for x in xrange(rev, stop - 1, -1):
1158 for x in xrange(rev, stop - 1, -1):
1160 if ff.match(x):
1159 if ff.match(x):
1161 wanted.discard(x)
1160 wanted.discard(x)
1162
1161
1163 def iterate():
1162 def iterate():
1164 if follow and not match.files():
1163 if follow and not match.files():
1165 ff = followfilter(onlyfirst=opts.get('follow_first'))
1164 ff = followfilter(onlyfirst=opts.get('follow_first'))
1166 def want(rev):
1165 def want(rev):
1167 return ff.match(rev) and rev in wanted
1166 return ff.match(rev) and rev in wanted
1168 else:
1167 else:
1169 def want(rev):
1168 def want(rev):
1170 return rev in wanted
1169 return rev in wanted
1171
1170
1172 for i, window in increasing_windows(0, len(revs)):
1171 for i, window in increasing_windows(0, len(revs)):
1173 change = util.cachefunc(repo.changectx)
1172 change = util.cachefunc(repo.changectx)
1174 nrevs = [rev for rev in revs[i:i + window] if want(rev)]
1173 nrevs = [rev for rev in revs[i:i + window] if want(rev)]
1175 for rev in sorted(nrevs):
1174 for rev in sorted(nrevs):
1176 fns = fncache.get(rev)
1175 fns = fncache.get(rev)
1177 ctx = change(rev)
1176 ctx = change(rev)
1178 if not fns:
1177 if not fns:
1179 def fns_generator():
1178 def fns_generator():
1180 for f in ctx.files():
1179 for f in ctx.files():
1181 if match(f):
1180 if match(f):
1182 yield f
1181 yield f
1183 fns = fns_generator()
1182 fns = fns_generator()
1184 prepare(ctx, fns)
1183 prepare(ctx, fns)
1185 for rev in nrevs:
1184 for rev in nrevs:
1186 yield change(rev)
1185 yield change(rev)
1187 return iterate()
1186 return iterate()
1188
1187
1189 def commit(ui, repo, commitfunc, pats, opts):
1188 def commit(ui, repo, commitfunc, pats, opts):
1190 '''commit the specified files or all outstanding changes'''
1189 '''commit the specified files or all outstanding changes'''
1191 date = opts.get('date')
1190 date = opts.get('date')
1192 if date:
1191 if date:
1193 opts['date'] = util.parsedate(date)
1192 opts['date'] = util.parsedate(date)
1194 message = logmessage(opts)
1193 message = logmessage(opts)
1195
1194
1196 # extract addremove carefully -- this function can be called from a command
1195 # extract addremove carefully -- this function can be called from a command
1197 # that doesn't support addremove
1196 # that doesn't support addremove
1198 if opts.get('addremove'):
1197 if opts.get('addremove'):
1199 addremove(repo, pats, opts)
1198 addremove(repo, pats, opts)
1200
1199
1201 return commitfunc(ui, repo, message, match(repo, pats, opts), opts)
1200 return commitfunc(ui, repo, message, match(repo, pats, opts), opts)
1202
1201
1203 def commiteditor(repo, ctx, subs):
1202 def commiteditor(repo, ctx, subs):
1204 if ctx.description():
1203 if ctx.description():
1205 return ctx.description()
1204 return ctx.description()
1206 return commitforceeditor(repo, ctx, subs)
1205 return commitforceeditor(repo, ctx, subs)
1207
1206
1208 def commitforceeditor(repo, ctx, subs):
1207 def commitforceeditor(repo, ctx, subs):
1209 edittext = []
1208 edittext = []
1210 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
1209 modified, added, removed = ctx.modified(), ctx.added(), ctx.removed()
1211 if ctx.description():
1210 if ctx.description():
1212 edittext.append(ctx.description())
1211 edittext.append(ctx.description())
1213 edittext.append("")
1212 edittext.append("")
1214 edittext.append("") # Empty line between message and comments.
1213 edittext.append("") # Empty line between message and comments.
1215 edittext.append(_("HG: Enter commit message."
1214 edittext.append(_("HG: Enter commit message."
1216 " Lines beginning with 'HG:' are removed."))
1215 " Lines beginning with 'HG:' are removed."))
1217 edittext.append(_("HG: Leave message empty to abort commit."))
1216 edittext.append(_("HG: Leave message empty to abort commit."))
1218 edittext.append("HG: --")
1217 edittext.append("HG: --")
1219 edittext.append(_("HG: user: %s") % ctx.user())
1218 edittext.append(_("HG: user: %s") % ctx.user())
1220 if ctx.p2():
1219 if ctx.p2():
1221 edittext.append(_("HG: branch merge"))
1220 edittext.append(_("HG: branch merge"))
1222 if ctx.branch():
1221 if ctx.branch():
1223 edittext.append(_("HG: branch '%s'")
1222 edittext.append(_("HG: branch '%s'")
1224 % encoding.tolocal(ctx.branch()))
1223 % encoding.tolocal(ctx.branch()))
1225 edittext.extend([_("HG: subrepo %s") % s for s in subs])
1224 edittext.extend([_("HG: subrepo %s") % s for s in subs])
1226 edittext.extend([_("HG: added %s") % f for f in added])
1225 edittext.extend([_("HG: added %s") % f for f in added])
1227 edittext.extend([_("HG: changed %s") % f for f in modified])
1226 edittext.extend([_("HG: changed %s") % f for f in modified])
1228 edittext.extend([_("HG: removed %s") % f for f in removed])
1227 edittext.extend([_("HG: removed %s") % f for f in removed])
1229 if not added and not modified and not removed:
1228 if not added and not modified and not removed:
1230 edittext.append(_("HG: no files changed"))
1229 edittext.append(_("HG: no files changed"))
1231 edittext.append("")
1230 edittext.append("")
1232 # run editor in the repository root
1231 # run editor in the repository root
1233 olddir = os.getcwd()
1232 olddir = os.getcwd()
1234 os.chdir(repo.root)
1233 os.chdir(repo.root)
1235 text = repo.ui.edit("\n".join(edittext), ctx.user())
1234 text = repo.ui.edit("\n".join(edittext), ctx.user())
1236 text = re.sub("(?m)^HG:.*\n", "", text)
1235 text = re.sub("(?m)^HG:.*\n", "", text)
1237 os.chdir(olddir)
1236 os.chdir(olddir)
1238
1237
1239 if not text.strip():
1238 if not text.strip():
1240 raise util.Abort(_("empty commit message"))
1239 raise util.Abort(_("empty commit message"))
1241
1240
1242 return text
1241 return text
@@ -1,207 +1,210 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 hg init a
3 hg init a
4 cd a
4 cd a
5 echo a > a
5 echo a > a
6 hg add a
6 hg add a
7 echo line 1 > b
7 echo line 1 > b
8 echo line 2 >> b
8 echo line 2 >> b
9 hg commit -l b -d '1000000 0' -u 'User Name <user@hostname>'
9 hg commit -l b -d '1000000 0' -u 'User Name <user@hostname>'
10 hg add b
10 hg add b
11 echo other 1 > c
11 echo other 1 > c
12 echo other 2 >> c
12 echo other 2 >> c
13 echo >> c
13 echo >> c
14 echo other 3 >> c
14 echo other 3 >> c
15 hg commit -l c -d '1100000 0' -u 'A. N. Other <other@place>'
15 hg commit -l c -d '1100000 0' -u 'A. N. Other <other@place>'
16 hg add c
16 hg add c
17 hg commit -m 'no person' -d '1200000 0' -u 'other@place'
17 hg commit -m 'no person' -d '1200000 0' -u 'other@place'
18 echo c >> c
18 echo c >> c
19 hg commit -m 'no user, no domain' -d '1300000 0' -u 'person'
19 hg commit -m 'no user, no domain' -d '1300000 0' -u 'person'
20 echo foo > .hg/branch
20 echo foo > .hg/branch
21 hg commit -m 'new branch' -d '1400000 0' -u 'person'
21 hg commit -m 'new branch' -d '1400000 0' -u 'person'
22 hg co -q 3
22 hg co -q 3
23 echo other 4 >> d
23 echo other 4 >> d
24 hg add d
24 hg add d
25 hg commit -m 'new head' -d '1500000 0' -u 'person'
25 hg commit -m 'new head' -d '1500000 0' -u 'person'
26 hg merge -q foo
26 hg merge -q foo
27 hg commit -m 'merge' -d '1500001 0' -u 'person'
27 hg commit -m 'merge' -d '1500001 0' -u 'person'
28 # second branch starting at nullrev
28 # second branch starting at nullrev
29 hg update null
29 hg update null
30 echo second > second
30 echo second > second
31 hg add second
31 hg add second
32 hg commit -m second -d '1000000 0' -u 'User Name <user@hostname>'
32 hg commit -m second -d '1000000 0' -u 'User Name <user@hostname>'
33 echo third > third
33 echo third > third
34 hg add third
34 hg add third
35 hg mv second fourth
35 hg mv second fourth
36 hg commit -m third -d "2020-01-01 10:01"
36 hg commit -m third -d "2020-01-01 10:01"
37
37
38 # make sure user/global hgrc does not affect tests
38 # make sure user/global hgrc does not affect tests
39 echo '[ui]' > .hg/hgrc
39 echo '[ui]' > .hg/hgrc
40 echo 'logtemplate =' >> .hg/hgrc
40 echo 'logtemplate =' >> .hg/hgrc
41 echo 'style =' >> .hg/hgrc
41 echo 'style =' >> .hg/hgrc
42
42
43 echo '# default style is like normal output'
43 echo '# default style is like normal output'
44 echo '# normal'
44 echo '# normal'
45 hg log > log.out
45 hg log > log.out
46 hg log --style default > style.out
46 hg log --style default > style.out
47 cmp log.out style.out || diff -u log.out style.out
47 cmp log.out style.out || diff -u log.out style.out
48 echo '# verbose'
48 echo '# verbose'
49 hg log -v > log.out
49 hg log -v > log.out
50 hg log -v --style default > style.out
50 hg log -v --style default > style.out
51 cmp log.out style.out || diff -u log.out style.out
51 cmp log.out style.out || diff -u log.out style.out
52 echo '# debug'
52 echo '# debug'
53 hg log --debug > log.out
53 hg log --debug > log.out
54 hg log --debug --style default > style.out
54 hg log --debug --style default > style.out
55 cmp log.out style.out || diff -u log.out style.out
55 cmp log.out style.out || diff -u log.out style.out
56
56
57 echo '# revision with no copies (used to print a traceback)'
57 echo '# revision with no copies (used to print a traceback)'
58 hg tip -v --template '\n'
58 hg tip -v --template '\n'
59
59
60 echo '# compact style works'
60 echo '# compact style works'
61 hg log --style compact
61 hg log --style compact
62 hg log -v --style compact
62 hg log -v --style compact
63 hg log --debug --style compact
63 hg log --debug --style compact
64
64
65 # Test xml styles
65 # Test xml styles
66 echo '# xml style works (--style xml)'
66 echo '# xml style works (--style xml)'
67 hg log --style xml
67 hg log --style xml
68 echo '# xml style works (-v --style xml)'
68 echo '# xml style works (-v --style xml)'
69 hg log -v --style xml
69 hg log -v --style xml
70 echo '# xml style works (--debug --style xml)'
70 echo '# xml style works (--debug --style xml)'
71 hg log --debug --style xml
71 hg log --debug --style xml
72
72
73 echo '# error if style not readable'
73 echo '# error if style not readable'
74 touch q
74 touch q
75 chmod 0 q
75 chmod 0 q
76 hg log --style ./q
76 hg log --style ./q
77
77
78 echo '# error if no style'
78 echo '# error if no style'
79 hg log --style notexist
79 hg log --style notexist
80
80
81 echo '# error if style missing key'
81 echo '# error if style missing key'
82 echo 'q = q' > t
82 echo 'q = q' > t
83 hg log --style ./t
83 hg log --style ./t
84
84
85 echo '# error if include fails'
85 echo '# error if include fails'
86 echo 'changeset = q' >> t
86 echo 'changeset = q' >> t
87 hg log --style ./t
87 hg log --style ./t
88
88
89 echo '# include works'
89 echo '# include works'
90 rm q
90 rm q
91 echo '{rev}' > q
91 echo '{rev}' > q
92 hg log --style ./t
92 hg log --style ./t
93
93
94 echo '# ui.style works'
94 echo '# ui.style works'
95 echo '[ui]' > .hg/hgrc
95 echo '[ui]' > .hg/hgrc
96 echo 'style = t' >> .hg/hgrc
96 echo 'style = t' >> .hg/hgrc
97 hg log
97 hg log
98
98
99 echo '# issue338'
99 echo '# issue338'
100 hg log --style=changelog > changelog
100 hg log --style=changelog > changelog
101 cat changelog
101 cat changelog
102
102
103 echo '# issue 2130'
104 hg heads --style changelog
105
103 echo "# keys work"
106 echo "# keys work"
104 for key in author branches date desc file_adds file_dels file_mods \
107 for key in author branches date desc file_adds file_dels file_mods \
105 file_copies file_copies_switch files \
108 file_copies file_copies_switch files \
106 manifest node parents rev tags diffstat extras; do
109 manifest node parents rev tags diffstat extras; do
107 for mode in '' --verbose --debug; do
110 for mode in '' --verbose --debug; do
108 hg log $mode --template "$key$mode: {$key}\n"
111 hg log $mode --template "$key$mode: {$key}\n"
109 done
112 done
110 done
113 done
111
114
112 echo '# filters work'
115 echo '# filters work'
113 hg log --template '{author|domain}\n'
116 hg log --template '{author|domain}\n'
114 hg log --template '{author|person}\n'
117 hg log --template '{author|person}\n'
115 hg log --template '{author|user}\n'
118 hg log --template '{author|user}\n'
116 hg log --template '{date|age}\n' > /dev/null || exit 1
119 hg log --template '{date|age}\n' > /dev/null || exit 1
117 hg log -l1 --template '{date|age}\n'
120 hg log -l1 --template '{date|age}\n'
118 hg log --template '{date|date}\n'
121 hg log --template '{date|date}\n'
119 hg log --template '{date|isodate}\n'
122 hg log --template '{date|isodate}\n'
120 hg log --template '{date|isodatesec}\n'
123 hg log --template '{date|isodatesec}\n'
121 hg log --template '{date|rfc822date}\n'
124 hg log --template '{date|rfc822date}\n'
122 hg log --template '{desc|firstline}\n'
125 hg log --template '{desc|firstline}\n'
123 hg log --template '{node|short}\n'
126 hg log --template '{node|short}\n'
124 hg log --template '<changeset author="{author|xmlescape}"/>\n'
127 hg log --template '<changeset author="{author|xmlescape}"/>\n'
125
128
126 echo '# formatnode filter works'
129 echo '# formatnode filter works'
127 echo '# quiet'
130 echo '# quiet'
128 hg -q log -r 0 --template '{node|formatnode}\n'
131 hg -q log -r 0 --template '{node|formatnode}\n'
129 echo '# normal'
132 echo '# normal'
130 hg log -r 0 --template '{node|formatnode}\n'
133 hg log -r 0 --template '{node|formatnode}\n'
131 echo '# verbose'
134 echo '# verbose'
132 hg -v log -r 0 --template '{node|formatnode}\n'
135 hg -v log -r 0 --template '{node|formatnode}\n'
133 echo '# debug'
136 echo '# debug'
134 hg --debug log -r 0 --template '{node|formatnode}\n'
137 hg --debug log -r 0 --template '{node|formatnode}\n'
135
138
136 echo '# error on syntax'
139 echo '# error on syntax'
137 echo 'x = "f' >> t
140 echo 'x = "f' >> t
138 hg log
141 hg log
139
142
140 cd ..
143 cd ..
141
144
142 echo '# latesttag'
145 echo '# latesttag'
143 hg init latesttag
146 hg init latesttag
144 cd latesttag
147 cd latesttag
145
148
146 echo a > file
149 echo a > file
147 hg ci -Am a -d '0 0'
150 hg ci -Am a -d '0 0'
148
151
149 echo b >> file
152 echo b >> file
150 hg ci -m b -d '1 0'
153 hg ci -m b -d '1 0'
151
154
152 echo c >> head1
155 echo c >> head1
153 hg ci -Am h1c -d '2 0'
156 hg ci -Am h1c -d '2 0'
154
157
155 hg update -q 1
158 hg update -q 1
156 echo d >> head2
159 echo d >> head2
157 hg ci -Am h2d -d '3 0'
160 hg ci -Am h2d -d '3 0'
158
161
159 echo e >> head2
162 echo e >> head2
160 hg ci -m h2e -d '4 0'
163 hg ci -m h2e -d '4 0'
161
164
162 hg merge -q
165 hg merge -q
163 hg ci -m merge -d '5 0'
166 hg ci -m merge -d '5 0'
164
167
165 echo '# No tag set'
168 echo '# No tag set'
166 hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
169 hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
167
170
168 echo '# one common tag: longuest path wins'
171 echo '# one common tag: longuest path wins'
169 hg tag -r 1 -m t1 -d '6 0' t1
172 hg tag -r 1 -m t1 -d '6 0' t1
170 hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
173 hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
171
174
172 echo '# one ancestor tag: more recent wins'
175 echo '# one ancestor tag: more recent wins'
173 hg tag -r 2 -m t2 -d '7 0' t2
176 hg tag -r 2 -m t2 -d '7 0' t2
174 hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
177 hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
175
178
176 echo '# two branch tags: more recent wins'
179 echo '# two branch tags: more recent wins'
177 hg tag -r 3 -m t3 -d '8 0' t3
180 hg tag -r 3 -m t3 -d '8 0' t3
178 hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
181 hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
179
182
180 echo '# merged tag overrides'
183 echo '# merged tag overrides'
181 hg tag -r 5 -m t5 -d '9 0' t5
184 hg tag -r 5 -m t5 -d '9 0' t5
182 hg tag -r 3 -m at3 -d '10 0' at3
185 hg tag -r 3 -m at3 -d '10 0' at3
183 hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
186 hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
184 cd ..
187 cd ..
185
188
186 echo '# style path expansion (issue1948)'
189 echo '# style path expansion (issue1948)'
187 mkdir -p home/styles
190 mkdir -p home/styles
188 cat > home/styles/teststyle <<EOF
191 cat > home/styles/teststyle <<EOF
189 changeset = 'test {rev}:{node|short}\n'
192 changeset = 'test {rev}:{node|short}\n'
190 EOF
193 EOF
191 HOME=`pwd`/home; export HOME
194 HOME=`pwd`/home; export HOME
192 cat > latesttag/.hg/hgrc <<EOF
195 cat > latesttag/.hg/hgrc <<EOF
193 [ui]
196 [ui]
194 style = ~/styles/teststyle
197 style = ~/styles/teststyle
195 EOF
198 EOF
196 hg -R latesttag tip
199 hg -R latesttag tip
197
200
198 echo '# test recursive showlist template (issue1989)'
201 echo '# test recursive showlist template (issue1989)'
199 cat > style1989 <<EOF
202 cat > style1989 <<EOF
200 changeset = '{file_mods}{manifest}{extras}'
203 changeset = '{file_mods}{manifest}{extras}'
201 file_mod = 'M|{author|person}\n'
204 file_mod = 'M|{author|person}\n'
202 manifest = '{rev},{author}\n'
205 manifest = '{rev},{author}\n'
203 extra = '{key}: {author}\n'
206 extra = '{key}: {author}\n'
204 EOF
207 EOF
205 hg -R latesttag log -r tip --style=style1989
208 hg -R latesttag log -r tip --style=style1989
206
209
207 echo '# done'
210 echo '# done'
@@ -1,1072 +1,1089 b''
1 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
1 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
2 created new head
2 created new head
3 # default style is like normal output
3 # default style is like normal output
4 # normal
4 # normal
5 # verbose
5 # verbose
6 # debug
6 # debug
7 # revision with no copies (used to print a traceback)
7 # revision with no copies (used to print a traceback)
8
8
9 # compact style works
9 # compact style works
10 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
10 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
11 third
11 third
12
12
13 7:-1 29114dbae42b 1970-01-12 13:46 +0000 user
13 7:-1 29114dbae42b 1970-01-12 13:46 +0000 user
14 second
14 second
15
15
16 6:5,4 c7b487c6c50e 1970-01-18 08:40 +0000 person
16 6:5,4 c7b487c6c50e 1970-01-18 08:40 +0000 person
17 merge
17 merge
18
18
19 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
19 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
20 new head
20 new head
21
21
22 4 32a18f097fcc 1970-01-17 04:53 +0000 person
22 4 32a18f097fcc 1970-01-17 04:53 +0000 person
23 new branch
23 new branch
24
24
25 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
25 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
26 no user, no domain
26 no user, no domain
27
27
28 2 97054abb4ab8 1970-01-14 21:20 +0000 other
28 2 97054abb4ab8 1970-01-14 21:20 +0000 other
29 no person
29 no person
30
30
31 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
31 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
32 other 1
32 other 1
33
33
34 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
34 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
35 line 1
35 line 1
36
36
37 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
37 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
38 third
38 third
39
39
40 7:-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
40 7:-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
41 second
41 second
42
42
43 6:5,4 c7b487c6c50e 1970-01-18 08:40 +0000 person
43 6:5,4 c7b487c6c50e 1970-01-18 08:40 +0000 person
44 merge
44 merge
45
45
46 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
46 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
47 new head
47 new head
48
48
49 4 32a18f097fcc 1970-01-17 04:53 +0000 person
49 4 32a18f097fcc 1970-01-17 04:53 +0000 person
50 new branch
50 new branch
51
51
52 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
52 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
53 no user, no domain
53 no user, no domain
54
54
55 2 97054abb4ab8 1970-01-14 21:20 +0000 other@place
55 2 97054abb4ab8 1970-01-14 21:20 +0000 other@place
56 no person
56 no person
57
57
58 1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
58 1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
59 other 1
59 other 1
60 other 2
60 other 2
61
61
62 other 3
62 other 3
63
63
64 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
64 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
65 line 1
65 line 1
66 line 2
66 line 2
67
67
68 8[tip]:7,-1 95c24699272e 2020-01-01 10:01 +0000 test
68 8[tip]:7,-1 95c24699272e 2020-01-01 10:01 +0000 test
69 third
69 third
70
70
71 7:-1,-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
71 7:-1,-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
72 second
72 second
73
73
74 6:5,4 c7b487c6c50e 1970-01-18 08:40 +0000 person
74 6:5,4 c7b487c6c50e 1970-01-18 08:40 +0000 person
75 merge
75 merge
76
76
77 5:3,-1 13207e5a10d9 1970-01-18 08:40 +0000 person
77 5:3,-1 13207e5a10d9 1970-01-18 08:40 +0000 person
78 new head
78 new head
79
79
80 4:3,-1 32a18f097fcc 1970-01-17 04:53 +0000 person
80 4:3,-1 32a18f097fcc 1970-01-17 04:53 +0000 person
81 new branch
81 new branch
82
82
83 3:2,-1 10e46f2dcbf4 1970-01-16 01:06 +0000 person
83 3:2,-1 10e46f2dcbf4 1970-01-16 01:06 +0000 person
84 no user, no domain
84 no user, no domain
85
85
86 2:1,-1 97054abb4ab8 1970-01-14 21:20 +0000 other@place
86 2:1,-1 97054abb4ab8 1970-01-14 21:20 +0000 other@place
87 no person
87 no person
88
88
89 1:0,-1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
89 1:0,-1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
90 other 1
90 other 1
91 other 2
91 other 2
92
92
93 other 3
93 other 3
94
94
95 0:-1,-1 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
95 0:-1,-1 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
96 line 1
96 line 1
97 line 2
97 line 2
98
98
99 # xml style works (--style xml)
99 # xml style works (--style xml)
100 <?xml version="1.0"?>
100 <?xml version="1.0"?>
101 <log>
101 <log>
102 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
102 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
103 <tag>tip</tag>
103 <tag>tip</tag>
104 <author email="test">test</author>
104 <author email="test">test</author>
105 <date>2020-01-01T10:01:00+00:00</date>
105 <date>2020-01-01T10:01:00+00:00</date>
106 <msg xml:space="preserve">third</msg>
106 <msg xml:space="preserve">third</msg>
107 </logentry>
107 </logentry>
108 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
108 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
109 <parent revision="-1" node="0000000000000000000000000000000000000000" />
109 <parent revision="-1" node="0000000000000000000000000000000000000000" />
110 <author email="user@hostname">User Name</author>
110 <author email="user@hostname">User Name</author>
111 <date>1970-01-12T13:46:40+00:00</date>
111 <date>1970-01-12T13:46:40+00:00</date>
112 <msg xml:space="preserve">second</msg>
112 <msg xml:space="preserve">second</msg>
113 </logentry>
113 </logentry>
114 <logentry revision="6" node="c7b487c6c50ef1cf464cafdc4f4f5e615fc5999f">
114 <logentry revision="6" node="c7b487c6c50ef1cf464cafdc4f4f5e615fc5999f">
115 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
115 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
116 <parent revision="4" node="32a18f097fcccf76ef282f62f8a85b3adf8d13c4" />
116 <parent revision="4" node="32a18f097fcccf76ef282f62f8a85b3adf8d13c4" />
117 <author email="person">person</author>
117 <author email="person">person</author>
118 <date>1970-01-18T08:40:01+00:00</date>
118 <date>1970-01-18T08:40:01+00:00</date>
119 <msg xml:space="preserve">merge</msg>
119 <msg xml:space="preserve">merge</msg>
120 </logentry>
120 </logentry>
121 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
121 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
122 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
122 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
123 <author email="person">person</author>
123 <author email="person">person</author>
124 <date>1970-01-18T08:40:00+00:00</date>
124 <date>1970-01-18T08:40:00+00:00</date>
125 <msg xml:space="preserve">new head</msg>
125 <msg xml:space="preserve">new head</msg>
126 </logentry>
126 </logentry>
127 <logentry revision="4" node="32a18f097fcccf76ef282f62f8a85b3adf8d13c4">
127 <logentry revision="4" node="32a18f097fcccf76ef282f62f8a85b3adf8d13c4">
128 <branch>foo</branch>
128 <branch>foo</branch>
129 <author email="person">person</author>
129 <author email="person">person</author>
130 <date>1970-01-17T04:53:20+00:00</date>
130 <date>1970-01-17T04:53:20+00:00</date>
131 <msg xml:space="preserve">new branch</msg>
131 <msg xml:space="preserve">new branch</msg>
132 </logentry>
132 </logentry>
133 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
133 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
134 <author email="person">person</author>
134 <author email="person">person</author>
135 <date>1970-01-16T01:06:40+00:00</date>
135 <date>1970-01-16T01:06:40+00:00</date>
136 <msg xml:space="preserve">no user, no domain</msg>
136 <msg xml:space="preserve">no user, no domain</msg>
137 </logentry>
137 </logentry>
138 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
138 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
139 <author email="other@place">other</author>
139 <author email="other@place">other</author>
140 <date>1970-01-14T21:20:00+00:00</date>
140 <date>1970-01-14T21:20:00+00:00</date>
141 <msg xml:space="preserve">no person</msg>
141 <msg xml:space="preserve">no person</msg>
142 </logentry>
142 </logentry>
143 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
143 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
144 <author email="other@place">A. N. Other</author>
144 <author email="other@place">A. N. Other</author>
145 <date>1970-01-13T17:33:20+00:00</date>
145 <date>1970-01-13T17:33:20+00:00</date>
146 <msg xml:space="preserve">other 1
146 <msg xml:space="preserve">other 1
147 other 2
147 other 2
148
148
149 other 3</msg>
149 other 3</msg>
150 </logentry>
150 </logentry>
151 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
151 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
152 <author email="user@hostname">User Name</author>
152 <author email="user@hostname">User Name</author>
153 <date>1970-01-12T13:46:40+00:00</date>
153 <date>1970-01-12T13:46:40+00:00</date>
154 <msg xml:space="preserve">line 1
154 <msg xml:space="preserve">line 1
155 line 2</msg>
155 line 2</msg>
156 </logentry>
156 </logentry>
157 </log>
157 </log>
158 # xml style works (-v --style xml)
158 # xml style works (-v --style xml)
159 <?xml version="1.0"?>
159 <?xml version="1.0"?>
160 <log>
160 <log>
161 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
161 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
162 <tag>tip</tag>
162 <tag>tip</tag>
163 <author email="test">test</author>
163 <author email="test">test</author>
164 <date>2020-01-01T10:01:00+00:00</date>
164 <date>2020-01-01T10:01:00+00:00</date>
165 <msg xml:space="preserve">third</msg>
165 <msg xml:space="preserve">third</msg>
166 <paths>
166 <paths>
167 <path action="A">fourth</path>
167 <path action="A">fourth</path>
168 <path action="A">third</path>
168 <path action="A">third</path>
169 <path action="R">second</path>
169 <path action="R">second</path>
170 </paths>
170 </paths>
171 <copies>
171 <copies>
172 <copy source="second">fourth</copy>
172 <copy source="second">fourth</copy>
173 </copies>
173 </copies>
174 </logentry>
174 </logentry>
175 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
175 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
176 <parent revision="-1" node="0000000000000000000000000000000000000000" />
176 <parent revision="-1" node="0000000000000000000000000000000000000000" />
177 <author email="user@hostname">User Name</author>
177 <author email="user@hostname">User Name</author>
178 <date>1970-01-12T13:46:40+00:00</date>
178 <date>1970-01-12T13:46:40+00:00</date>
179 <msg xml:space="preserve">second</msg>
179 <msg xml:space="preserve">second</msg>
180 <paths>
180 <paths>
181 <path action="A">second</path>
181 <path action="A">second</path>
182 </paths>
182 </paths>
183 </logentry>
183 </logentry>
184 <logentry revision="6" node="c7b487c6c50ef1cf464cafdc4f4f5e615fc5999f">
184 <logentry revision="6" node="c7b487c6c50ef1cf464cafdc4f4f5e615fc5999f">
185 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
185 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
186 <parent revision="4" node="32a18f097fcccf76ef282f62f8a85b3adf8d13c4" />
186 <parent revision="4" node="32a18f097fcccf76ef282f62f8a85b3adf8d13c4" />
187 <author email="person">person</author>
187 <author email="person">person</author>
188 <date>1970-01-18T08:40:01+00:00</date>
188 <date>1970-01-18T08:40:01+00:00</date>
189 <msg xml:space="preserve">merge</msg>
189 <msg xml:space="preserve">merge</msg>
190 <paths>
190 <paths>
191 </paths>
191 </paths>
192 </logentry>
192 </logentry>
193 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
193 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
194 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
194 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
195 <author email="person">person</author>
195 <author email="person">person</author>
196 <date>1970-01-18T08:40:00+00:00</date>
196 <date>1970-01-18T08:40:00+00:00</date>
197 <msg xml:space="preserve">new head</msg>
197 <msg xml:space="preserve">new head</msg>
198 <paths>
198 <paths>
199 <path action="A">d</path>
199 <path action="A">d</path>
200 </paths>
200 </paths>
201 </logentry>
201 </logentry>
202 <logentry revision="4" node="32a18f097fcccf76ef282f62f8a85b3adf8d13c4">
202 <logentry revision="4" node="32a18f097fcccf76ef282f62f8a85b3adf8d13c4">
203 <branch>foo</branch>
203 <branch>foo</branch>
204 <author email="person">person</author>
204 <author email="person">person</author>
205 <date>1970-01-17T04:53:20+00:00</date>
205 <date>1970-01-17T04:53:20+00:00</date>
206 <msg xml:space="preserve">new branch</msg>
206 <msg xml:space="preserve">new branch</msg>
207 <paths>
207 <paths>
208 </paths>
208 </paths>
209 </logentry>
209 </logentry>
210 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
210 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
211 <author email="person">person</author>
211 <author email="person">person</author>
212 <date>1970-01-16T01:06:40+00:00</date>
212 <date>1970-01-16T01:06:40+00:00</date>
213 <msg xml:space="preserve">no user, no domain</msg>
213 <msg xml:space="preserve">no user, no domain</msg>
214 <paths>
214 <paths>
215 <path action="M">c</path>
215 <path action="M">c</path>
216 </paths>
216 </paths>
217 </logentry>
217 </logentry>
218 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
218 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
219 <author email="other@place">other</author>
219 <author email="other@place">other</author>
220 <date>1970-01-14T21:20:00+00:00</date>
220 <date>1970-01-14T21:20:00+00:00</date>
221 <msg xml:space="preserve">no person</msg>
221 <msg xml:space="preserve">no person</msg>
222 <paths>
222 <paths>
223 <path action="A">c</path>
223 <path action="A">c</path>
224 </paths>
224 </paths>
225 </logentry>
225 </logentry>
226 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
226 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
227 <author email="other@place">A. N. Other</author>
227 <author email="other@place">A. N. Other</author>
228 <date>1970-01-13T17:33:20+00:00</date>
228 <date>1970-01-13T17:33:20+00:00</date>
229 <msg xml:space="preserve">other 1
229 <msg xml:space="preserve">other 1
230 other 2
230 other 2
231
231
232 other 3</msg>
232 other 3</msg>
233 <paths>
233 <paths>
234 <path action="A">b</path>
234 <path action="A">b</path>
235 </paths>
235 </paths>
236 </logentry>
236 </logentry>
237 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
237 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
238 <author email="user@hostname">User Name</author>
238 <author email="user@hostname">User Name</author>
239 <date>1970-01-12T13:46:40+00:00</date>
239 <date>1970-01-12T13:46:40+00:00</date>
240 <msg xml:space="preserve">line 1
240 <msg xml:space="preserve">line 1
241 line 2</msg>
241 line 2</msg>
242 <paths>
242 <paths>
243 <path action="A">a</path>
243 <path action="A">a</path>
244 </paths>
244 </paths>
245 </logentry>
245 </logentry>
246 </log>
246 </log>
247 # xml style works (--debug --style xml)
247 # xml style works (--debug --style xml)
248 <?xml version="1.0"?>
248 <?xml version="1.0"?>
249 <log>
249 <log>
250 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
250 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
251 <tag>tip</tag>
251 <tag>tip</tag>
252 <parent revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453" />
252 <parent revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453" />
253 <parent revision="-1" node="0000000000000000000000000000000000000000" />
253 <parent revision="-1" node="0000000000000000000000000000000000000000" />
254 <author email="test">test</author>
254 <author email="test">test</author>
255 <date>2020-01-01T10:01:00+00:00</date>
255 <date>2020-01-01T10:01:00+00:00</date>
256 <msg xml:space="preserve">third</msg>
256 <msg xml:space="preserve">third</msg>
257 <paths>
257 <paths>
258 <path action="A">fourth</path>
258 <path action="A">fourth</path>
259 <path action="A">third</path>
259 <path action="A">third</path>
260 <path action="R">second</path>
260 <path action="R">second</path>
261 </paths>
261 </paths>
262 <copies>
262 <copies>
263 <copy source="second">fourth</copy>
263 <copy source="second">fourth</copy>
264 </copies>
264 </copies>
265 <extra key="branch">default</extra>
265 <extra key="branch">default</extra>
266 </logentry>
266 </logentry>
267 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
267 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
268 <parent revision="-1" node="0000000000000000000000000000000000000000" />
268 <parent revision="-1" node="0000000000000000000000000000000000000000" />
269 <parent revision="-1" node="0000000000000000000000000000000000000000" />
269 <parent revision="-1" node="0000000000000000000000000000000000000000" />
270 <author email="user@hostname">User Name</author>
270 <author email="user@hostname">User Name</author>
271 <date>1970-01-12T13:46:40+00:00</date>
271 <date>1970-01-12T13:46:40+00:00</date>
272 <msg xml:space="preserve">second</msg>
272 <msg xml:space="preserve">second</msg>
273 <paths>
273 <paths>
274 <path action="A">second</path>
274 <path action="A">second</path>
275 </paths>
275 </paths>
276 <extra key="branch">default</extra>
276 <extra key="branch">default</extra>
277 </logentry>
277 </logentry>
278 <logentry revision="6" node="c7b487c6c50ef1cf464cafdc4f4f5e615fc5999f">
278 <logentry revision="6" node="c7b487c6c50ef1cf464cafdc4f4f5e615fc5999f">
279 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
279 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
280 <parent revision="4" node="32a18f097fcccf76ef282f62f8a85b3adf8d13c4" />
280 <parent revision="4" node="32a18f097fcccf76ef282f62f8a85b3adf8d13c4" />
281 <author email="person">person</author>
281 <author email="person">person</author>
282 <date>1970-01-18T08:40:01+00:00</date>
282 <date>1970-01-18T08:40:01+00:00</date>
283 <msg xml:space="preserve">merge</msg>
283 <msg xml:space="preserve">merge</msg>
284 <paths>
284 <paths>
285 </paths>
285 </paths>
286 <extra key="branch">default</extra>
286 <extra key="branch">default</extra>
287 </logentry>
287 </logentry>
288 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
288 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
289 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
289 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
290 <parent revision="-1" node="0000000000000000000000000000000000000000" />
290 <parent revision="-1" node="0000000000000000000000000000000000000000" />
291 <author email="person">person</author>
291 <author email="person">person</author>
292 <date>1970-01-18T08:40:00+00:00</date>
292 <date>1970-01-18T08:40:00+00:00</date>
293 <msg xml:space="preserve">new head</msg>
293 <msg xml:space="preserve">new head</msg>
294 <paths>
294 <paths>
295 <path action="A">d</path>
295 <path action="A">d</path>
296 </paths>
296 </paths>
297 <extra key="branch">default</extra>
297 <extra key="branch">default</extra>
298 </logentry>
298 </logentry>
299 <logentry revision="4" node="32a18f097fcccf76ef282f62f8a85b3adf8d13c4">
299 <logentry revision="4" node="32a18f097fcccf76ef282f62f8a85b3adf8d13c4">
300 <branch>foo</branch>
300 <branch>foo</branch>
301 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
301 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
302 <parent revision="-1" node="0000000000000000000000000000000000000000" />
302 <parent revision="-1" node="0000000000000000000000000000000000000000" />
303 <author email="person">person</author>
303 <author email="person">person</author>
304 <date>1970-01-17T04:53:20+00:00</date>
304 <date>1970-01-17T04:53:20+00:00</date>
305 <msg xml:space="preserve">new branch</msg>
305 <msg xml:space="preserve">new branch</msg>
306 <paths>
306 <paths>
307 </paths>
307 </paths>
308 <extra key="branch">foo</extra>
308 <extra key="branch">foo</extra>
309 </logentry>
309 </logentry>
310 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
310 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
311 <parent revision="2" node="97054abb4ab824450e9164180baf491ae0078465" />
311 <parent revision="2" node="97054abb4ab824450e9164180baf491ae0078465" />
312 <parent revision="-1" node="0000000000000000000000000000000000000000" />
312 <parent revision="-1" node="0000000000000000000000000000000000000000" />
313 <author email="person">person</author>
313 <author email="person">person</author>
314 <date>1970-01-16T01:06:40+00:00</date>
314 <date>1970-01-16T01:06:40+00:00</date>
315 <msg xml:space="preserve">no user, no domain</msg>
315 <msg xml:space="preserve">no user, no domain</msg>
316 <paths>
316 <paths>
317 <path action="M">c</path>
317 <path action="M">c</path>
318 </paths>
318 </paths>
319 <extra key="branch">default</extra>
319 <extra key="branch">default</extra>
320 </logentry>
320 </logentry>
321 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
321 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
322 <parent revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965" />
322 <parent revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965" />
323 <parent revision="-1" node="0000000000000000000000000000000000000000" />
323 <parent revision="-1" node="0000000000000000000000000000000000000000" />
324 <author email="other@place">other</author>
324 <author email="other@place">other</author>
325 <date>1970-01-14T21:20:00+00:00</date>
325 <date>1970-01-14T21:20:00+00:00</date>
326 <msg xml:space="preserve">no person</msg>
326 <msg xml:space="preserve">no person</msg>
327 <paths>
327 <paths>
328 <path action="A">c</path>
328 <path action="A">c</path>
329 </paths>
329 </paths>
330 <extra key="branch">default</extra>
330 <extra key="branch">default</extra>
331 </logentry>
331 </logentry>
332 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
332 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
333 <parent revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f" />
333 <parent revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f" />
334 <parent revision="-1" node="0000000000000000000000000000000000000000" />
334 <parent revision="-1" node="0000000000000000000000000000000000000000" />
335 <author email="other@place">A. N. Other</author>
335 <author email="other@place">A. N. Other</author>
336 <date>1970-01-13T17:33:20+00:00</date>
336 <date>1970-01-13T17:33:20+00:00</date>
337 <msg xml:space="preserve">other 1
337 <msg xml:space="preserve">other 1
338 other 2
338 other 2
339
339
340 other 3</msg>
340 other 3</msg>
341 <paths>
341 <paths>
342 <path action="A">b</path>
342 <path action="A">b</path>
343 </paths>
343 </paths>
344 <extra key="branch">default</extra>
344 <extra key="branch">default</extra>
345 </logentry>
345 </logentry>
346 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
346 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
347 <parent revision="-1" node="0000000000000000000000000000000000000000" />
347 <parent revision="-1" node="0000000000000000000000000000000000000000" />
348 <parent revision="-1" node="0000000000000000000000000000000000000000" />
348 <parent revision="-1" node="0000000000000000000000000000000000000000" />
349 <author email="user@hostname">User Name</author>
349 <author email="user@hostname">User Name</author>
350 <date>1970-01-12T13:46:40+00:00</date>
350 <date>1970-01-12T13:46:40+00:00</date>
351 <msg xml:space="preserve">line 1
351 <msg xml:space="preserve">line 1
352 line 2</msg>
352 line 2</msg>
353 <paths>
353 <paths>
354 <path action="A">a</path>
354 <path action="A">a</path>
355 </paths>
355 </paths>
356 <extra key="branch">default</extra>
356 <extra key="branch">default</extra>
357 </logentry>
357 </logentry>
358 </log>
358 </log>
359 # error if style not readable
359 # error if style not readable
360 abort: Permission denied: ./q
360 abort: Permission denied: ./q
361 # error if no style
361 # error if no style
362 abort: style not found: notexist
362 abort: style not found: notexist
363 # error if style missing key
363 # error if style missing key
364 abort: ./t: no key named 'changeset'
364 abort: ./t: no key named 'changeset'
365 # error if include fails
365 # error if include fails
366 abort: template file ./q: Permission denied
366 abort: template file ./q: Permission denied
367 # include works
367 # include works
368 8
368 8
369 7
369 7
370 6
370 6
371 5
371 5
372 4
372 4
373 3
373 3
374 2
374 2
375 1
375 1
376 0
376 0
377 # ui.style works
377 # ui.style works
378 8
378 8
379 7
379 7
380 6
380 6
381 5
381 5
382 4
382 4
383 3
383 3
384 2
384 2
385 1
385 1
386 0
386 0
387 # issue338
387 # issue338
388 2020-01-01 test <test>
388 2020-01-01 test <test>
389
389
390 * fourth, second, third:
390 * fourth, second, third:
391 third
391 third
392 [95c24699272e] [tip]
392 [95c24699272e] [tip]
393
393
394 1970-01-12 User Name <user@hostname>
394 1970-01-12 User Name <user@hostname>
395
395
396 * second:
396 * second:
397 second
397 second
398 [29114dbae42b]
398 [29114dbae42b]
399
399
400 1970-01-18 person <person>
400 1970-01-18 person <person>
401
401
402 * merge
402 * merge
403 [c7b487c6c50e]
403 [c7b487c6c50e]
404
404
405 * d:
405 * d:
406 new head
406 new head
407 [13207e5a10d9]
407 [13207e5a10d9]
408
408
409 1970-01-17 person <person>
409 1970-01-17 person <person>
410
410
411 * new branch
411 * new branch
412 [32a18f097fcc] <foo>
412 [32a18f097fcc] <foo>
413
413
414 1970-01-16 person <person>
414 1970-01-16 person <person>
415
415
416 * c:
416 * c:
417 no user, no domain
417 no user, no domain
418 [10e46f2dcbf4]
418 [10e46f2dcbf4]
419
419
420 1970-01-14 other <other@place>
420 1970-01-14 other <other@place>
421
421
422 * c:
422 * c:
423 no person
423 no person
424 [97054abb4ab8]
424 [97054abb4ab8]
425
425
426 1970-01-13 A. N. Other <other@place>
426 1970-01-13 A. N. Other <other@place>
427
427
428 * b:
428 * b:
429 other 1 other 2
429 other 1 other 2
430
430
431 other 3
431 other 3
432 [b608e9d1a3f0]
432 [b608e9d1a3f0]
433
433
434 1970-01-12 User Name <user@hostname>
434 1970-01-12 User Name <user@hostname>
435
435
436 * a:
436 * a:
437 line 1 line 2
437 line 1 line 2
438 [1e4e1b8f71e0]
438 [1e4e1b8f71e0]
439
439
440 # issue 2130
441 2020-01-01 test <test>
442
443 * fourth, second, third:
444 third
445 [95c24699272e] [tip]
446
447 1970-01-18 person <person>
448
449 * merge
450 [c7b487c6c50e]
451
452 1970-01-17 person <person>
453
454 * new branch
455 [32a18f097fcc] <foo>
456
440 # keys work
457 # keys work
441 author: test
458 author: test
442 author: User Name <user@hostname>
459 author: User Name <user@hostname>
443 author: person
460 author: person
444 author: person
461 author: person
445 author: person
462 author: person
446 author: person
463 author: person
447 author: other@place
464 author: other@place
448 author: A. N. Other <other@place>
465 author: A. N. Other <other@place>
449 author: User Name <user@hostname>
466 author: User Name <user@hostname>
450 author--verbose: test
467 author--verbose: test
451 author--verbose: User Name <user@hostname>
468 author--verbose: User Name <user@hostname>
452 author--verbose: person
469 author--verbose: person
453 author--verbose: person
470 author--verbose: person
454 author--verbose: person
471 author--verbose: person
455 author--verbose: person
472 author--verbose: person
456 author--verbose: other@place
473 author--verbose: other@place
457 author--verbose: A. N. Other <other@place>
474 author--verbose: A. N. Other <other@place>
458 author--verbose: User Name <user@hostname>
475 author--verbose: User Name <user@hostname>
459 author--debug: test
476 author--debug: test
460 author--debug: User Name <user@hostname>
477 author--debug: User Name <user@hostname>
461 author--debug: person
478 author--debug: person
462 author--debug: person
479 author--debug: person
463 author--debug: person
480 author--debug: person
464 author--debug: person
481 author--debug: person
465 author--debug: other@place
482 author--debug: other@place
466 author--debug: A. N. Other <other@place>
483 author--debug: A. N. Other <other@place>
467 author--debug: User Name <user@hostname>
484 author--debug: User Name <user@hostname>
468 branches:
485 branches:
469 branches:
486 branches:
470 branches:
487 branches:
471 branches:
488 branches:
472 branches: foo
489 branches: foo
473 branches:
490 branches:
474 branches:
491 branches:
475 branches:
492 branches:
476 branches:
493 branches:
477 branches--verbose:
494 branches--verbose:
478 branches--verbose:
495 branches--verbose:
479 branches--verbose:
496 branches--verbose:
480 branches--verbose:
497 branches--verbose:
481 branches--verbose: foo
498 branches--verbose: foo
482 branches--verbose:
499 branches--verbose:
483 branches--verbose:
500 branches--verbose:
484 branches--verbose:
501 branches--verbose:
485 branches--verbose:
502 branches--verbose:
486 branches--debug:
503 branches--debug:
487 branches--debug:
504 branches--debug:
488 branches--debug:
505 branches--debug:
489 branches--debug:
506 branches--debug:
490 branches--debug: foo
507 branches--debug: foo
491 branches--debug:
508 branches--debug:
492 branches--debug:
509 branches--debug:
493 branches--debug:
510 branches--debug:
494 branches--debug:
511 branches--debug:
495 date: 1577872860.00
512 date: 1577872860.00
496 date: 1000000.00
513 date: 1000000.00
497 date: 1500001.00
514 date: 1500001.00
498 date: 1500000.00
515 date: 1500000.00
499 date: 1400000.00
516 date: 1400000.00
500 date: 1300000.00
517 date: 1300000.00
501 date: 1200000.00
518 date: 1200000.00
502 date: 1100000.00
519 date: 1100000.00
503 date: 1000000.00
520 date: 1000000.00
504 date--verbose: 1577872860.00
521 date--verbose: 1577872860.00
505 date--verbose: 1000000.00
522 date--verbose: 1000000.00
506 date--verbose: 1500001.00
523 date--verbose: 1500001.00
507 date--verbose: 1500000.00
524 date--verbose: 1500000.00
508 date--verbose: 1400000.00
525 date--verbose: 1400000.00
509 date--verbose: 1300000.00
526 date--verbose: 1300000.00
510 date--verbose: 1200000.00
527 date--verbose: 1200000.00
511 date--verbose: 1100000.00
528 date--verbose: 1100000.00
512 date--verbose: 1000000.00
529 date--verbose: 1000000.00
513 date--debug: 1577872860.00
530 date--debug: 1577872860.00
514 date--debug: 1000000.00
531 date--debug: 1000000.00
515 date--debug: 1500001.00
532 date--debug: 1500001.00
516 date--debug: 1500000.00
533 date--debug: 1500000.00
517 date--debug: 1400000.00
534 date--debug: 1400000.00
518 date--debug: 1300000.00
535 date--debug: 1300000.00
519 date--debug: 1200000.00
536 date--debug: 1200000.00
520 date--debug: 1100000.00
537 date--debug: 1100000.00
521 date--debug: 1000000.00
538 date--debug: 1000000.00
522 desc: third
539 desc: third
523 desc: second
540 desc: second
524 desc: merge
541 desc: merge
525 desc: new head
542 desc: new head
526 desc: new branch
543 desc: new branch
527 desc: no user, no domain
544 desc: no user, no domain
528 desc: no person
545 desc: no person
529 desc: other 1
546 desc: other 1
530 other 2
547 other 2
531
548
532 other 3
549 other 3
533 desc: line 1
550 desc: line 1
534 line 2
551 line 2
535 desc--verbose: third
552 desc--verbose: third
536 desc--verbose: second
553 desc--verbose: second
537 desc--verbose: merge
554 desc--verbose: merge
538 desc--verbose: new head
555 desc--verbose: new head
539 desc--verbose: new branch
556 desc--verbose: new branch
540 desc--verbose: no user, no domain
557 desc--verbose: no user, no domain
541 desc--verbose: no person
558 desc--verbose: no person
542 desc--verbose: other 1
559 desc--verbose: other 1
543 other 2
560 other 2
544
561
545 other 3
562 other 3
546 desc--verbose: line 1
563 desc--verbose: line 1
547 line 2
564 line 2
548 desc--debug: third
565 desc--debug: third
549 desc--debug: second
566 desc--debug: second
550 desc--debug: merge
567 desc--debug: merge
551 desc--debug: new head
568 desc--debug: new head
552 desc--debug: new branch
569 desc--debug: new branch
553 desc--debug: no user, no domain
570 desc--debug: no user, no domain
554 desc--debug: no person
571 desc--debug: no person
555 desc--debug: other 1
572 desc--debug: other 1
556 other 2
573 other 2
557
574
558 other 3
575 other 3
559 desc--debug: line 1
576 desc--debug: line 1
560 line 2
577 line 2
561 file_adds: fourth third
578 file_adds: fourth third
562 file_adds: second
579 file_adds: second
563 file_adds:
580 file_adds:
564 file_adds: d
581 file_adds: d
565 file_adds:
582 file_adds:
566 file_adds:
583 file_adds:
567 file_adds: c
584 file_adds: c
568 file_adds: b
585 file_adds: b
569 file_adds: a
586 file_adds: a
570 file_adds--verbose: fourth third
587 file_adds--verbose: fourth third
571 file_adds--verbose: second
588 file_adds--verbose: second
572 file_adds--verbose:
589 file_adds--verbose:
573 file_adds--verbose: d
590 file_adds--verbose: d
574 file_adds--verbose:
591 file_adds--verbose:
575 file_adds--verbose:
592 file_adds--verbose:
576 file_adds--verbose: c
593 file_adds--verbose: c
577 file_adds--verbose: b
594 file_adds--verbose: b
578 file_adds--verbose: a
595 file_adds--verbose: a
579 file_adds--debug: fourth third
596 file_adds--debug: fourth third
580 file_adds--debug: second
597 file_adds--debug: second
581 file_adds--debug:
598 file_adds--debug:
582 file_adds--debug: d
599 file_adds--debug: d
583 file_adds--debug:
600 file_adds--debug:
584 file_adds--debug:
601 file_adds--debug:
585 file_adds--debug: c
602 file_adds--debug: c
586 file_adds--debug: b
603 file_adds--debug: b
587 file_adds--debug: a
604 file_adds--debug: a
588 file_dels: second
605 file_dels: second
589 file_dels:
606 file_dels:
590 file_dels:
607 file_dels:
591 file_dels:
608 file_dels:
592 file_dels:
609 file_dels:
593 file_dels:
610 file_dels:
594 file_dels:
611 file_dels:
595 file_dels:
612 file_dels:
596 file_dels:
613 file_dels:
597 file_dels--verbose: second
614 file_dels--verbose: second
598 file_dels--verbose:
615 file_dels--verbose:
599 file_dels--verbose:
616 file_dels--verbose:
600 file_dels--verbose:
617 file_dels--verbose:
601 file_dels--verbose:
618 file_dels--verbose:
602 file_dels--verbose:
619 file_dels--verbose:
603 file_dels--verbose:
620 file_dels--verbose:
604 file_dels--verbose:
621 file_dels--verbose:
605 file_dels--verbose:
622 file_dels--verbose:
606 file_dels--debug: second
623 file_dels--debug: second
607 file_dels--debug:
624 file_dels--debug:
608 file_dels--debug:
625 file_dels--debug:
609 file_dels--debug:
626 file_dels--debug:
610 file_dels--debug:
627 file_dels--debug:
611 file_dels--debug:
628 file_dels--debug:
612 file_dels--debug:
629 file_dels--debug:
613 file_dels--debug:
630 file_dels--debug:
614 file_dels--debug:
631 file_dels--debug:
615 file_mods:
632 file_mods:
616 file_mods:
633 file_mods:
617 file_mods:
634 file_mods:
618 file_mods:
635 file_mods:
619 file_mods:
636 file_mods:
620 file_mods: c
637 file_mods: c
621 file_mods:
638 file_mods:
622 file_mods:
639 file_mods:
623 file_mods:
640 file_mods:
624 file_mods--verbose:
641 file_mods--verbose:
625 file_mods--verbose:
642 file_mods--verbose:
626 file_mods--verbose:
643 file_mods--verbose:
627 file_mods--verbose:
644 file_mods--verbose:
628 file_mods--verbose:
645 file_mods--verbose:
629 file_mods--verbose: c
646 file_mods--verbose: c
630 file_mods--verbose:
647 file_mods--verbose:
631 file_mods--verbose:
648 file_mods--verbose:
632 file_mods--verbose:
649 file_mods--verbose:
633 file_mods--debug:
650 file_mods--debug:
634 file_mods--debug:
651 file_mods--debug:
635 file_mods--debug:
652 file_mods--debug:
636 file_mods--debug:
653 file_mods--debug:
637 file_mods--debug:
654 file_mods--debug:
638 file_mods--debug: c
655 file_mods--debug: c
639 file_mods--debug:
656 file_mods--debug:
640 file_mods--debug:
657 file_mods--debug:
641 file_mods--debug:
658 file_mods--debug:
642 file_copies: fourth (second)
659 file_copies: fourth (second)
643 file_copies:
660 file_copies:
644 file_copies:
661 file_copies:
645 file_copies:
662 file_copies:
646 file_copies:
663 file_copies:
647 file_copies:
664 file_copies:
648 file_copies:
665 file_copies:
649 file_copies:
666 file_copies:
650 file_copies:
667 file_copies:
651 file_copies--verbose: fourth (second)
668 file_copies--verbose: fourth (second)
652 file_copies--verbose:
669 file_copies--verbose:
653 file_copies--verbose:
670 file_copies--verbose:
654 file_copies--verbose:
671 file_copies--verbose:
655 file_copies--verbose:
672 file_copies--verbose:
656 file_copies--verbose:
673 file_copies--verbose:
657 file_copies--verbose:
674 file_copies--verbose:
658 file_copies--verbose:
675 file_copies--verbose:
659 file_copies--verbose:
676 file_copies--verbose:
660 file_copies--debug: fourth (second)
677 file_copies--debug: fourth (second)
661 file_copies--debug:
678 file_copies--debug:
662 file_copies--debug:
679 file_copies--debug:
663 file_copies--debug:
680 file_copies--debug:
664 file_copies--debug:
681 file_copies--debug:
665 file_copies--debug:
682 file_copies--debug:
666 file_copies--debug:
683 file_copies--debug:
667 file_copies--debug:
684 file_copies--debug:
668 file_copies--debug:
685 file_copies--debug:
669 file_copies_switch:
686 file_copies_switch:
670 file_copies_switch:
687 file_copies_switch:
671 file_copies_switch:
688 file_copies_switch:
672 file_copies_switch:
689 file_copies_switch:
673 file_copies_switch:
690 file_copies_switch:
674 file_copies_switch:
691 file_copies_switch:
675 file_copies_switch:
692 file_copies_switch:
676 file_copies_switch:
693 file_copies_switch:
677 file_copies_switch:
694 file_copies_switch:
678 file_copies_switch--verbose:
695 file_copies_switch--verbose:
679 file_copies_switch--verbose:
696 file_copies_switch--verbose:
680 file_copies_switch--verbose:
697 file_copies_switch--verbose:
681 file_copies_switch--verbose:
698 file_copies_switch--verbose:
682 file_copies_switch--verbose:
699 file_copies_switch--verbose:
683 file_copies_switch--verbose:
700 file_copies_switch--verbose:
684 file_copies_switch--verbose:
701 file_copies_switch--verbose:
685 file_copies_switch--verbose:
702 file_copies_switch--verbose:
686 file_copies_switch--verbose:
703 file_copies_switch--verbose:
687 file_copies_switch--debug:
704 file_copies_switch--debug:
688 file_copies_switch--debug:
705 file_copies_switch--debug:
689 file_copies_switch--debug:
706 file_copies_switch--debug:
690 file_copies_switch--debug:
707 file_copies_switch--debug:
691 file_copies_switch--debug:
708 file_copies_switch--debug:
692 file_copies_switch--debug:
709 file_copies_switch--debug:
693 file_copies_switch--debug:
710 file_copies_switch--debug:
694 file_copies_switch--debug:
711 file_copies_switch--debug:
695 file_copies_switch--debug:
712 file_copies_switch--debug:
696 files: fourth second third
713 files: fourth second third
697 files: second
714 files: second
698 files:
715 files:
699 files: d
716 files: d
700 files:
717 files:
701 files: c
718 files: c
702 files: c
719 files: c
703 files: b
720 files: b
704 files: a
721 files: a
705 files--verbose: fourth second third
722 files--verbose: fourth second third
706 files--verbose: second
723 files--verbose: second
707 files--verbose:
724 files--verbose:
708 files--verbose: d
725 files--verbose: d
709 files--verbose:
726 files--verbose:
710 files--verbose: c
727 files--verbose: c
711 files--verbose: c
728 files--verbose: c
712 files--verbose: b
729 files--verbose: b
713 files--verbose: a
730 files--verbose: a
714 files--debug: fourth second third
731 files--debug: fourth second third
715 files--debug: second
732 files--debug: second
716 files--debug:
733 files--debug:
717 files--debug: d
734 files--debug: d
718 files--debug:
735 files--debug:
719 files--debug: c
736 files--debug: c
720 files--debug: c
737 files--debug: c
721 files--debug: b
738 files--debug: b
722 files--debug: a
739 files--debug: a
723 manifest: 8:94961b75a2da
740 manifest: 8:94961b75a2da
724 manifest: 7:f2dbc354b94e
741 manifest: 7:f2dbc354b94e
725 manifest: 6:91015e9dbdd7
742 manifest: 6:91015e9dbdd7
726 manifest: 5:4dc3def4f9b4
743 manifest: 5:4dc3def4f9b4
727 manifest: 4:90ae8dda64e1
744 manifest: 4:90ae8dda64e1
728 manifest: 3:cb5a1327723b
745 manifest: 3:cb5a1327723b
729 manifest: 2:6e0e82995c35
746 manifest: 2:6e0e82995c35
730 manifest: 1:4e8d705b1e53
747 manifest: 1:4e8d705b1e53
731 manifest: 0:a0c8bcbbb45c
748 manifest: 0:a0c8bcbbb45c
732 manifest--verbose: 8:94961b75a2da
749 manifest--verbose: 8:94961b75a2da
733 manifest--verbose: 7:f2dbc354b94e
750 manifest--verbose: 7:f2dbc354b94e
734 manifest--verbose: 6:91015e9dbdd7
751 manifest--verbose: 6:91015e9dbdd7
735 manifest--verbose: 5:4dc3def4f9b4
752 manifest--verbose: 5:4dc3def4f9b4
736 manifest--verbose: 4:90ae8dda64e1
753 manifest--verbose: 4:90ae8dda64e1
737 manifest--verbose: 3:cb5a1327723b
754 manifest--verbose: 3:cb5a1327723b
738 manifest--verbose: 2:6e0e82995c35
755 manifest--verbose: 2:6e0e82995c35
739 manifest--verbose: 1:4e8d705b1e53
756 manifest--verbose: 1:4e8d705b1e53
740 manifest--verbose: 0:a0c8bcbbb45c
757 manifest--verbose: 0:a0c8bcbbb45c
741 manifest--debug: 8:94961b75a2da554b4df6fb599e5bfc7d48de0c64
758 manifest--debug: 8:94961b75a2da554b4df6fb599e5bfc7d48de0c64
742 manifest--debug: 7:f2dbc354b94e5ec0b4f10680ee0cee816101d0bf
759 manifest--debug: 7:f2dbc354b94e5ec0b4f10680ee0cee816101d0bf
743 manifest--debug: 6:91015e9dbdd76a6791085d12b0a0ec7fcd22ffbf
760 manifest--debug: 6:91015e9dbdd76a6791085d12b0a0ec7fcd22ffbf
744 manifest--debug: 5:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
761 manifest--debug: 5:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
745 manifest--debug: 4:90ae8dda64e1a876c792bccb9af66284f6018363
762 manifest--debug: 4:90ae8dda64e1a876c792bccb9af66284f6018363
746 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
763 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
747 manifest--debug: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
764 manifest--debug: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
748 manifest--debug: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
765 manifest--debug: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
749 manifest--debug: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
766 manifest--debug: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
750 node: 95c24699272ef57d062b8bccc32c878bf841784a
767 node: 95c24699272ef57d062b8bccc32c878bf841784a
751 node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
768 node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
752 node: c7b487c6c50ef1cf464cafdc4f4f5e615fc5999f
769 node: c7b487c6c50ef1cf464cafdc4f4f5e615fc5999f
753 node: 13207e5a10d9fd28ec424934298e176197f2c67f
770 node: 13207e5a10d9fd28ec424934298e176197f2c67f
754 node: 32a18f097fcccf76ef282f62f8a85b3adf8d13c4
771 node: 32a18f097fcccf76ef282f62f8a85b3adf8d13c4
755 node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
772 node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
756 node: 97054abb4ab824450e9164180baf491ae0078465
773 node: 97054abb4ab824450e9164180baf491ae0078465
757 node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
774 node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
758 node: 1e4e1b8f71e05681d422154f5421e385fec3454f
775 node: 1e4e1b8f71e05681d422154f5421e385fec3454f
759 node--verbose: 95c24699272ef57d062b8bccc32c878bf841784a
776 node--verbose: 95c24699272ef57d062b8bccc32c878bf841784a
760 node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
777 node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
761 node--verbose: c7b487c6c50ef1cf464cafdc4f4f5e615fc5999f
778 node--verbose: c7b487c6c50ef1cf464cafdc4f4f5e615fc5999f
762 node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
779 node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
763 node--verbose: 32a18f097fcccf76ef282f62f8a85b3adf8d13c4
780 node--verbose: 32a18f097fcccf76ef282f62f8a85b3adf8d13c4
764 node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
781 node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
765 node--verbose: 97054abb4ab824450e9164180baf491ae0078465
782 node--verbose: 97054abb4ab824450e9164180baf491ae0078465
766 node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
783 node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
767 node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
784 node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
768 node--debug: 95c24699272ef57d062b8bccc32c878bf841784a
785 node--debug: 95c24699272ef57d062b8bccc32c878bf841784a
769 node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
786 node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
770 node--debug: c7b487c6c50ef1cf464cafdc4f4f5e615fc5999f
787 node--debug: c7b487c6c50ef1cf464cafdc4f4f5e615fc5999f
771 node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
788 node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
772 node--debug: 32a18f097fcccf76ef282f62f8a85b3adf8d13c4
789 node--debug: 32a18f097fcccf76ef282f62f8a85b3adf8d13c4
773 node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
790 node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
774 node--debug: 97054abb4ab824450e9164180baf491ae0078465
791 node--debug: 97054abb4ab824450e9164180baf491ae0078465
775 node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
792 node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
776 node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
793 node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
777 parents:
794 parents:
778 parents: -1:000000000000
795 parents: -1:000000000000
779 parents: 5:13207e5a10d9 4:32a18f097fcc
796 parents: 5:13207e5a10d9 4:32a18f097fcc
780 parents: 3:10e46f2dcbf4
797 parents: 3:10e46f2dcbf4
781 parents:
798 parents:
782 parents:
799 parents:
783 parents:
800 parents:
784 parents:
801 parents:
785 parents:
802 parents:
786 parents--verbose:
803 parents--verbose:
787 parents--verbose: -1:000000000000
804 parents--verbose: -1:000000000000
788 parents--verbose: 5:13207e5a10d9 4:32a18f097fcc
805 parents--verbose: 5:13207e5a10d9 4:32a18f097fcc
789 parents--verbose: 3:10e46f2dcbf4
806 parents--verbose: 3:10e46f2dcbf4
790 parents--verbose:
807 parents--verbose:
791 parents--verbose:
808 parents--verbose:
792 parents--verbose:
809 parents--verbose:
793 parents--verbose:
810 parents--verbose:
794 parents--verbose:
811 parents--verbose:
795 parents--debug: 7:29114dbae42b9f078cf2714dbe3a86bba8ec7453 -1:0000000000000000000000000000000000000000
812 parents--debug: 7:29114dbae42b9f078cf2714dbe3a86bba8ec7453 -1:0000000000000000000000000000000000000000
796 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
813 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
797 parents--debug: 5:13207e5a10d9fd28ec424934298e176197f2c67f 4:32a18f097fcccf76ef282f62f8a85b3adf8d13c4
814 parents--debug: 5:13207e5a10d9fd28ec424934298e176197f2c67f 4:32a18f097fcccf76ef282f62f8a85b3adf8d13c4
798 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
815 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
799 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
816 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
800 parents--debug: 2:97054abb4ab824450e9164180baf491ae0078465 -1:0000000000000000000000000000000000000000
817 parents--debug: 2:97054abb4ab824450e9164180baf491ae0078465 -1:0000000000000000000000000000000000000000
801 parents--debug: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965 -1:0000000000000000000000000000000000000000
818 parents--debug: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965 -1:0000000000000000000000000000000000000000
802 parents--debug: 0:1e4e1b8f71e05681d422154f5421e385fec3454f -1:0000000000000000000000000000000000000000
819 parents--debug: 0:1e4e1b8f71e05681d422154f5421e385fec3454f -1:0000000000000000000000000000000000000000
803 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
820 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
804 rev: 8
821 rev: 8
805 rev: 7
822 rev: 7
806 rev: 6
823 rev: 6
807 rev: 5
824 rev: 5
808 rev: 4
825 rev: 4
809 rev: 3
826 rev: 3
810 rev: 2
827 rev: 2
811 rev: 1
828 rev: 1
812 rev: 0
829 rev: 0
813 rev--verbose: 8
830 rev--verbose: 8
814 rev--verbose: 7
831 rev--verbose: 7
815 rev--verbose: 6
832 rev--verbose: 6
816 rev--verbose: 5
833 rev--verbose: 5
817 rev--verbose: 4
834 rev--verbose: 4
818 rev--verbose: 3
835 rev--verbose: 3
819 rev--verbose: 2
836 rev--verbose: 2
820 rev--verbose: 1
837 rev--verbose: 1
821 rev--verbose: 0
838 rev--verbose: 0
822 rev--debug: 8
839 rev--debug: 8
823 rev--debug: 7
840 rev--debug: 7
824 rev--debug: 6
841 rev--debug: 6
825 rev--debug: 5
842 rev--debug: 5
826 rev--debug: 4
843 rev--debug: 4
827 rev--debug: 3
844 rev--debug: 3
828 rev--debug: 2
845 rev--debug: 2
829 rev--debug: 1
846 rev--debug: 1
830 rev--debug: 0
847 rev--debug: 0
831 tags: tip
848 tags: tip
832 tags:
849 tags:
833 tags:
850 tags:
834 tags:
851 tags:
835 tags:
852 tags:
836 tags:
853 tags:
837 tags:
854 tags:
838 tags:
855 tags:
839 tags:
856 tags:
840 tags--verbose: tip
857 tags--verbose: tip
841 tags--verbose:
858 tags--verbose:
842 tags--verbose:
859 tags--verbose:
843 tags--verbose:
860 tags--verbose:
844 tags--verbose:
861 tags--verbose:
845 tags--verbose:
862 tags--verbose:
846 tags--verbose:
863 tags--verbose:
847 tags--verbose:
864 tags--verbose:
848 tags--verbose:
865 tags--verbose:
849 tags--debug: tip
866 tags--debug: tip
850 tags--debug:
867 tags--debug:
851 tags--debug:
868 tags--debug:
852 tags--debug:
869 tags--debug:
853 tags--debug:
870 tags--debug:
854 tags--debug:
871 tags--debug:
855 tags--debug:
872 tags--debug:
856 tags--debug:
873 tags--debug:
857 tags--debug:
874 tags--debug:
858 diffstat: 3: +2/-1
875 diffstat: 3: +2/-1
859 diffstat: 1: +1/-0
876 diffstat: 1: +1/-0
860 diffstat: 0: +0/-0
877 diffstat: 0: +0/-0
861 diffstat: 1: +1/-0
878 diffstat: 1: +1/-0
862 diffstat: 0: +0/-0
879 diffstat: 0: +0/-0
863 diffstat: 1: +1/-0
880 diffstat: 1: +1/-0
864 diffstat: 1: +4/-0
881 diffstat: 1: +4/-0
865 diffstat: 1: +2/-0
882 diffstat: 1: +2/-0
866 diffstat: 1: +1/-0
883 diffstat: 1: +1/-0
867 diffstat--verbose: 3: +2/-1
884 diffstat--verbose: 3: +2/-1
868 diffstat--verbose: 1: +1/-0
885 diffstat--verbose: 1: +1/-0
869 diffstat--verbose: 0: +0/-0
886 diffstat--verbose: 0: +0/-0
870 diffstat--verbose: 1: +1/-0
887 diffstat--verbose: 1: +1/-0
871 diffstat--verbose: 0: +0/-0
888 diffstat--verbose: 0: +0/-0
872 diffstat--verbose: 1: +1/-0
889 diffstat--verbose: 1: +1/-0
873 diffstat--verbose: 1: +4/-0
890 diffstat--verbose: 1: +4/-0
874 diffstat--verbose: 1: +2/-0
891 diffstat--verbose: 1: +2/-0
875 diffstat--verbose: 1: +1/-0
892 diffstat--verbose: 1: +1/-0
876 diffstat--debug: 3: +2/-1
893 diffstat--debug: 3: +2/-1
877 diffstat--debug: 1: +1/-0
894 diffstat--debug: 1: +1/-0
878 diffstat--debug: 0: +0/-0
895 diffstat--debug: 0: +0/-0
879 diffstat--debug: 1: +1/-0
896 diffstat--debug: 1: +1/-0
880 diffstat--debug: 0: +0/-0
897 diffstat--debug: 0: +0/-0
881 diffstat--debug: 1: +1/-0
898 diffstat--debug: 1: +1/-0
882 diffstat--debug: 1: +4/-0
899 diffstat--debug: 1: +4/-0
883 diffstat--debug: 1: +2/-0
900 diffstat--debug: 1: +2/-0
884 diffstat--debug: 1: +1/-0
901 diffstat--debug: 1: +1/-0
885 extras: branch=default
902 extras: branch=default
886 extras: branch=default
903 extras: branch=default
887 extras: branch=default
904 extras: branch=default
888 extras: branch=default
905 extras: branch=default
889 extras: branch=foo
906 extras: branch=foo
890 extras: branch=default
907 extras: branch=default
891 extras: branch=default
908 extras: branch=default
892 extras: branch=default
909 extras: branch=default
893 extras: branch=default
910 extras: branch=default
894 extras--verbose: branch=default
911 extras--verbose: branch=default
895 extras--verbose: branch=default
912 extras--verbose: branch=default
896 extras--verbose: branch=default
913 extras--verbose: branch=default
897 extras--verbose: branch=default
914 extras--verbose: branch=default
898 extras--verbose: branch=foo
915 extras--verbose: branch=foo
899 extras--verbose: branch=default
916 extras--verbose: branch=default
900 extras--verbose: branch=default
917 extras--verbose: branch=default
901 extras--verbose: branch=default
918 extras--verbose: branch=default
902 extras--verbose: branch=default
919 extras--verbose: branch=default
903 extras--debug: branch=default
920 extras--debug: branch=default
904 extras--debug: branch=default
921 extras--debug: branch=default
905 extras--debug: branch=default
922 extras--debug: branch=default
906 extras--debug: branch=default
923 extras--debug: branch=default
907 extras--debug: branch=foo
924 extras--debug: branch=foo
908 extras--debug: branch=default
925 extras--debug: branch=default
909 extras--debug: branch=default
926 extras--debug: branch=default
910 extras--debug: branch=default
927 extras--debug: branch=default
911 extras--debug: branch=default
928 extras--debug: branch=default
912 # filters work
929 # filters work
913
930
914 hostname
931 hostname
915
932
916
933
917
934
918
935
919 place
936 place
920 place
937 place
921 hostname
938 hostname
922 test
939 test
923 User Name
940 User Name
924 person
941 person
925 person
942 person
926 person
943 person
927 person
944 person
928 other
945 other
929 A. N. Other
946 A. N. Other
930 User Name
947 User Name
931 test
948 test
932 user
949 user
933 person
950 person
934 person
951 person
935 person
952 person
936 person
953 person
937 other
954 other
938 other
955 other
939 user
956 user
940 in the future
957 in the future
941 Wed Jan 01 10:01:00 2020 +0000
958 Wed Jan 01 10:01:00 2020 +0000
942 Mon Jan 12 13:46:40 1970 +0000
959 Mon Jan 12 13:46:40 1970 +0000
943 Sun Jan 18 08:40:01 1970 +0000
960 Sun Jan 18 08:40:01 1970 +0000
944 Sun Jan 18 08:40:00 1970 +0000
961 Sun Jan 18 08:40:00 1970 +0000
945 Sat Jan 17 04:53:20 1970 +0000
962 Sat Jan 17 04:53:20 1970 +0000
946 Fri Jan 16 01:06:40 1970 +0000
963 Fri Jan 16 01:06:40 1970 +0000
947 Wed Jan 14 21:20:00 1970 +0000
964 Wed Jan 14 21:20:00 1970 +0000
948 Tue Jan 13 17:33:20 1970 +0000
965 Tue Jan 13 17:33:20 1970 +0000
949 Mon Jan 12 13:46:40 1970 +0000
966 Mon Jan 12 13:46:40 1970 +0000
950 2020-01-01 10:01 +0000
967 2020-01-01 10:01 +0000
951 1970-01-12 13:46 +0000
968 1970-01-12 13:46 +0000
952 1970-01-18 08:40 +0000
969 1970-01-18 08:40 +0000
953 1970-01-18 08:40 +0000
970 1970-01-18 08:40 +0000
954 1970-01-17 04:53 +0000
971 1970-01-17 04:53 +0000
955 1970-01-16 01:06 +0000
972 1970-01-16 01:06 +0000
956 1970-01-14 21:20 +0000
973 1970-01-14 21:20 +0000
957 1970-01-13 17:33 +0000
974 1970-01-13 17:33 +0000
958 1970-01-12 13:46 +0000
975 1970-01-12 13:46 +0000
959 2020-01-01 10:01:00 +0000
976 2020-01-01 10:01:00 +0000
960 1970-01-12 13:46:40 +0000
977 1970-01-12 13:46:40 +0000
961 1970-01-18 08:40:01 +0000
978 1970-01-18 08:40:01 +0000
962 1970-01-18 08:40:00 +0000
979 1970-01-18 08:40:00 +0000
963 1970-01-17 04:53:20 +0000
980 1970-01-17 04:53:20 +0000
964 1970-01-16 01:06:40 +0000
981 1970-01-16 01:06:40 +0000
965 1970-01-14 21:20:00 +0000
982 1970-01-14 21:20:00 +0000
966 1970-01-13 17:33:20 +0000
983 1970-01-13 17:33:20 +0000
967 1970-01-12 13:46:40 +0000
984 1970-01-12 13:46:40 +0000
968 Wed, 01 Jan 2020 10:01:00 +0000
985 Wed, 01 Jan 2020 10:01:00 +0000
969 Mon, 12 Jan 1970 13:46:40 +0000
986 Mon, 12 Jan 1970 13:46:40 +0000
970 Sun, 18 Jan 1970 08:40:01 +0000
987 Sun, 18 Jan 1970 08:40:01 +0000
971 Sun, 18 Jan 1970 08:40:00 +0000
988 Sun, 18 Jan 1970 08:40:00 +0000
972 Sat, 17 Jan 1970 04:53:20 +0000
989 Sat, 17 Jan 1970 04:53:20 +0000
973 Fri, 16 Jan 1970 01:06:40 +0000
990 Fri, 16 Jan 1970 01:06:40 +0000
974 Wed, 14 Jan 1970 21:20:00 +0000
991 Wed, 14 Jan 1970 21:20:00 +0000
975 Tue, 13 Jan 1970 17:33:20 +0000
992 Tue, 13 Jan 1970 17:33:20 +0000
976 Mon, 12 Jan 1970 13:46:40 +0000
993 Mon, 12 Jan 1970 13:46:40 +0000
977 third
994 third
978 second
995 second
979 merge
996 merge
980 new head
997 new head
981 new branch
998 new branch
982 no user, no domain
999 no user, no domain
983 no person
1000 no person
984 other 1
1001 other 1
985 line 1
1002 line 1
986 95c24699272e
1003 95c24699272e
987 29114dbae42b
1004 29114dbae42b
988 c7b487c6c50e
1005 c7b487c6c50e
989 13207e5a10d9
1006 13207e5a10d9
990 32a18f097fcc
1007 32a18f097fcc
991 10e46f2dcbf4
1008 10e46f2dcbf4
992 97054abb4ab8
1009 97054abb4ab8
993 b608e9d1a3f0
1010 b608e9d1a3f0
994 1e4e1b8f71e0
1011 1e4e1b8f71e0
995 <changeset author="test"/>
1012 <changeset author="test"/>
996 <changeset author="User Name &lt;user@hostname&gt;"/>
1013 <changeset author="User Name &lt;user@hostname&gt;"/>
997 <changeset author="person"/>
1014 <changeset author="person"/>
998 <changeset author="person"/>
1015 <changeset author="person"/>
999 <changeset author="person"/>
1016 <changeset author="person"/>
1000 <changeset author="person"/>
1017 <changeset author="person"/>
1001 <changeset author="other@place"/>
1018 <changeset author="other@place"/>
1002 <changeset author="A. N. Other &lt;other@place&gt;"/>
1019 <changeset author="A. N. Other &lt;other@place&gt;"/>
1003 <changeset author="User Name &lt;user@hostname&gt;"/>
1020 <changeset author="User Name &lt;user@hostname&gt;"/>
1004 # formatnode filter works
1021 # formatnode filter works
1005 # quiet
1022 # quiet
1006 1e4e1b8f71e0
1023 1e4e1b8f71e0
1007 # normal
1024 # normal
1008 1e4e1b8f71e0
1025 1e4e1b8f71e0
1009 # verbose
1026 # verbose
1010 1e4e1b8f71e0
1027 1e4e1b8f71e0
1011 # debug
1028 # debug
1012 1e4e1b8f71e05681d422154f5421e385fec3454f
1029 1e4e1b8f71e05681d422154f5421e385fec3454f
1013 # error on syntax
1030 # error on syntax
1014 abort: t:3: unmatched quotes
1031 abort: t:3: unmatched quotes
1015 # latesttag
1032 # latesttag
1016 adding file
1033 adding file
1017 adding head1
1034 adding head1
1018 adding head2
1035 adding head2
1019 created new head
1036 created new head
1020 # No tag set
1037 # No tag set
1021 5: null+5
1038 5: null+5
1022 4: null+4
1039 4: null+4
1023 3: null+3
1040 3: null+3
1024 2: null+3
1041 2: null+3
1025 1: null+2
1042 1: null+2
1026 0: null+1
1043 0: null+1
1027 # one common tag: longuest path wins
1044 # one common tag: longuest path wins
1028 6: t1+4
1045 6: t1+4
1029 5: t1+3
1046 5: t1+3
1030 4: t1+2
1047 4: t1+2
1031 3: t1+1
1048 3: t1+1
1032 2: t1+1
1049 2: t1+1
1033 1: t1+0
1050 1: t1+0
1034 0: null+1
1051 0: null+1
1035 # one ancestor tag: more recent wins
1052 # one ancestor tag: more recent wins
1036 7: t2+3
1053 7: t2+3
1037 6: t2+2
1054 6: t2+2
1038 5: t2+1
1055 5: t2+1
1039 4: t1+2
1056 4: t1+2
1040 3: t1+1
1057 3: t1+1
1041 2: t2+0
1058 2: t2+0
1042 1: t1+0
1059 1: t1+0
1043 0: null+1
1060 0: null+1
1044 # two branch tags: more recent wins
1061 # two branch tags: more recent wins
1045 8: t3+5
1062 8: t3+5
1046 7: t3+4
1063 7: t3+4
1047 6: t3+3
1064 6: t3+3
1048 5: t3+2
1065 5: t3+2
1049 4: t3+1
1066 4: t3+1
1050 3: t3+0
1067 3: t3+0
1051 2: t2+0
1068 2: t2+0
1052 1: t1+0
1069 1: t1+0
1053 0: null+1
1070 0: null+1
1054 # merged tag overrides
1071 # merged tag overrides
1055 10: t5+5
1072 10: t5+5
1056 9: t5+4
1073 9: t5+4
1057 8: t5+3
1074 8: t5+3
1058 7: t5+2
1075 7: t5+2
1059 6: t5+1
1076 6: t5+1
1060 5: t5+0
1077 5: t5+0
1061 4: at3:t3+1
1078 4: at3:t3+1
1062 3: at3:t3+0
1079 3: at3:t3+0
1063 2: t2+0
1080 2: t2+0
1064 1: t1+0
1081 1: t1+0
1065 0: null+1
1082 0: null+1
1066 # style path expansion (issue1948)
1083 # style path expansion (issue1948)
1067 test 10:dee8f28249af
1084 test 10:dee8f28249af
1068 # test recursive showlist template (issue1989)
1085 # test recursive showlist template (issue1989)
1069 M|test
1086 M|test
1070 10,test
1087 10,test
1071 branch: test
1088 branch: test
1072 # done
1089 # done
General Comments 0
You need to be logged in to leave comments. Login now