##// END OF EJS Templates
fix 'hg <not-log> -v --template foo' with revisions without copies
Alexis S. L. Carvalho -
r4351:3380eb6d default
parent child Browse files
Show More
@@ -1,776 +1,776 b''
1 # cmdutil.py - help for command processing in mercurial
1 # cmdutil.py - help for command processing in mercurial
2 #
2 #
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from demandload import demandload
8 from demandload import demandload
9 from node import *
9 from node import *
10 from i18n import gettext as _
10 from i18n import gettext as _
11 demandload(globals(), 'os sys')
11 demandload(globals(), 'os sys')
12 demandload(globals(), 'mdiff util templater patch')
12 demandload(globals(), 'mdiff util templater patch')
13
13
14 revrangesep = ':'
14 revrangesep = ':'
15
15
16 def revpair(repo, revs):
16 def revpair(repo, revs):
17 '''return pair of nodes, given list of revisions. second item can
17 '''return pair of nodes, given list of revisions. second item can
18 be None, meaning use working dir.'''
18 be None, meaning use working dir.'''
19
19
20 def revfix(repo, val, defval):
20 def revfix(repo, val, defval):
21 if not val and val != 0 and defval is not None:
21 if not val and val != 0 and defval is not None:
22 val = defval
22 val = defval
23 return repo.lookup(val)
23 return repo.lookup(val)
24
24
25 if not revs:
25 if not revs:
26 return repo.dirstate.parents()[0], None
26 return repo.dirstate.parents()[0], None
27 end = None
27 end = None
28 if len(revs) == 1:
28 if len(revs) == 1:
29 if revrangesep in revs[0]:
29 if revrangesep in revs[0]:
30 start, end = revs[0].split(revrangesep, 1)
30 start, end = revs[0].split(revrangesep, 1)
31 start = revfix(repo, start, 0)
31 start = revfix(repo, start, 0)
32 end = revfix(repo, end, repo.changelog.count() - 1)
32 end = revfix(repo, end, repo.changelog.count() - 1)
33 else:
33 else:
34 start = revfix(repo, revs[0], None)
34 start = revfix(repo, revs[0], None)
35 elif len(revs) == 2:
35 elif len(revs) == 2:
36 if revrangesep in revs[0] or revrangesep in revs[1]:
36 if revrangesep in revs[0] or revrangesep in revs[1]:
37 raise util.Abort(_('too many revisions specified'))
37 raise util.Abort(_('too many revisions specified'))
38 start = revfix(repo, revs[0], None)
38 start = revfix(repo, revs[0], None)
39 end = revfix(repo, revs[1], None)
39 end = revfix(repo, revs[1], None)
40 else:
40 else:
41 raise util.Abort(_('too many revisions specified'))
41 raise util.Abort(_('too many revisions specified'))
42 return start, end
42 return start, end
43
43
44 def revrange(repo, revs):
44 def revrange(repo, revs):
45 """Yield revision as strings from a list of revision specifications."""
45 """Yield revision as strings from a list of revision specifications."""
46
46
47 def revfix(repo, val, defval):
47 def revfix(repo, val, defval):
48 if not val and val != 0 and defval is not None:
48 if not val and val != 0 and defval is not None:
49 return defval
49 return defval
50 return repo.changelog.rev(repo.lookup(val))
50 return repo.changelog.rev(repo.lookup(val))
51
51
52 seen, l = {}, []
52 seen, l = {}, []
53 for spec in revs:
53 for spec in revs:
54 if revrangesep in spec:
54 if revrangesep in spec:
55 start, end = spec.split(revrangesep, 1)
55 start, end = spec.split(revrangesep, 1)
56 start = revfix(repo, start, 0)
56 start = revfix(repo, start, 0)
57 end = revfix(repo, end, repo.changelog.count() - 1)
57 end = revfix(repo, end, repo.changelog.count() - 1)
58 step = start > end and -1 or 1
58 step = start > end and -1 or 1
59 for rev in xrange(start, end+step, step):
59 for rev in xrange(start, end+step, step):
60 if rev in seen:
60 if rev in seen:
61 continue
61 continue
62 seen[rev] = 1
62 seen[rev] = 1
63 l.append(rev)
63 l.append(rev)
64 else:
64 else:
65 rev = revfix(repo, spec, None)
65 rev = revfix(repo, spec, None)
66 if rev in seen:
66 if rev in seen:
67 continue
67 continue
68 seen[rev] = 1
68 seen[rev] = 1
69 l.append(rev)
69 l.append(rev)
70
70
71 return l
71 return l
72
72
73 def make_filename(repo, pat, node,
73 def make_filename(repo, pat, node,
74 total=None, seqno=None, revwidth=None, pathname=None):
74 total=None, seqno=None, revwidth=None, pathname=None):
75 node_expander = {
75 node_expander = {
76 'H': lambda: hex(node),
76 'H': lambda: hex(node),
77 'R': lambda: str(repo.changelog.rev(node)),
77 'R': lambda: str(repo.changelog.rev(node)),
78 'h': lambda: short(node),
78 'h': lambda: short(node),
79 }
79 }
80 expander = {
80 expander = {
81 '%': lambda: '%',
81 '%': lambda: '%',
82 'b': lambda: os.path.basename(repo.root),
82 'b': lambda: os.path.basename(repo.root),
83 }
83 }
84
84
85 try:
85 try:
86 if node:
86 if node:
87 expander.update(node_expander)
87 expander.update(node_expander)
88 if node and revwidth is not None:
88 if node and revwidth is not None:
89 expander['r'] = (lambda:
89 expander['r'] = (lambda:
90 str(repo.changelog.rev(node)).zfill(revwidth))
90 str(repo.changelog.rev(node)).zfill(revwidth))
91 if total is not None:
91 if total is not None:
92 expander['N'] = lambda: str(total)
92 expander['N'] = lambda: str(total)
93 if seqno is not None:
93 if seqno is not None:
94 expander['n'] = lambda: str(seqno)
94 expander['n'] = lambda: str(seqno)
95 if total is not None and seqno is not None:
95 if total is not None and seqno is not None:
96 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
96 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
97 if pathname is not None:
97 if pathname is not None:
98 expander['s'] = lambda: os.path.basename(pathname)
98 expander['s'] = lambda: os.path.basename(pathname)
99 expander['d'] = lambda: os.path.dirname(pathname) or '.'
99 expander['d'] = lambda: os.path.dirname(pathname) or '.'
100 expander['p'] = lambda: pathname
100 expander['p'] = lambda: pathname
101
101
102 newname = []
102 newname = []
103 patlen = len(pat)
103 patlen = len(pat)
104 i = 0
104 i = 0
105 while i < patlen:
105 while i < patlen:
106 c = pat[i]
106 c = pat[i]
107 if c == '%':
107 if c == '%':
108 i += 1
108 i += 1
109 c = pat[i]
109 c = pat[i]
110 c = expander[c]()
110 c = expander[c]()
111 newname.append(c)
111 newname.append(c)
112 i += 1
112 i += 1
113 return ''.join(newname)
113 return ''.join(newname)
114 except KeyError, inst:
114 except KeyError, inst:
115 raise util.Abort(_("invalid format spec '%%%s' in output file name") %
115 raise util.Abort(_("invalid format spec '%%%s' in output file name") %
116 inst.args[0])
116 inst.args[0])
117
117
118 def make_file(repo, pat, node=None,
118 def make_file(repo, pat, node=None,
119 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
119 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
120 if not pat or pat == '-':
120 if not pat or pat == '-':
121 return 'w' in mode and sys.stdout or sys.stdin
121 return 'w' in mode and sys.stdout or sys.stdin
122 if hasattr(pat, 'write') and 'w' in mode:
122 if hasattr(pat, 'write') and 'w' in mode:
123 return pat
123 return pat
124 if hasattr(pat, 'read') and 'r' in mode:
124 if hasattr(pat, 'read') and 'r' in mode:
125 return pat
125 return pat
126 return open(make_filename(repo, pat, node, total, seqno, revwidth,
126 return open(make_filename(repo, pat, node, total, seqno, revwidth,
127 pathname),
127 pathname),
128 mode)
128 mode)
129
129
130 def matchpats(repo, pats=[], opts={}, head='', globbed=False):
130 def matchpats(repo, pats=[], opts={}, head='', globbed=False):
131 cwd = repo.getcwd()
131 cwd = repo.getcwd()
132 if not pats and cwd:
132 if not pats and cwd:
133 opts['include'] = [os.path.join(cwd, i)
133 opts['include'] = [os.path.join(cwd, i)
134 for i in opts.get('include', [])]
134 for i in opts.get('include', [])]
135 opts['exclude'] = [os.path.join(cwd, x)
135 opts['exclude'] = [os.path.join(cwd, x)
136 for x in opts.get('exclude', [])]
136 for x in opts.get('exclude', [])]
137 cwd = ''
137 cwd = ''
138 return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'),
138 return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'),
139 opts.get('exclude'), head, globbed=globbed)
139 opts.get('exclude'), head, globbed=globbed)
140
140
141 def walk(repo, pats=[], opts={}, node=None, head='', badmatch=None,
141 def walk(repo, pats=[], opts={}, node=None, head='', badmatch=None,
142 globbed=False):
142 globbed=False):
143 files, matchfn, anypats = matchpats(repo, pats, opts, head,
143 files, matchfn, anypats = matchpats(repo, pats, opts, head,
144 globbed=globbed)
144 globbed=globbed)
145 exact = dict.fromkeys(files)
145 exact = dict.fromkeys(files)
146 for src, fn in repo.walk(node=node, files=files, match=matchfn,
146 for src, fn in repo.walk(node=node, files=files, match=matchfn,
147 badmatch=badmatch):
147 badmatch=badmatch):
148 yield src, fn, util.pathto(repo.root, repo.getcwd(), fn), fn in exact
148 yield src, fn, util.pathto(repo.root, repo.getcwd(), fn), fn in exact
149
149
150 def findrenames(repo, added=None, removed=None, threshold=0.5):
150 def findrenames(repo, added=None, removed=None, threshold=0.5):
151 if added is None or removed is None:
151 if added is None or removed is None:
152 added, removed = repo.status()[1:3]
152 added, removed = repo.status()[1:3]
153 changes = repo.changelog.read(repo.dirstate.parents()[0])
153 changes = repo.changelog.read(repo.dirstate.parents()[0])
154 mf = repo.manifest.read(changes[0])
154 mf = repo.manifest.read(changes[0])
155 for a in added:
155 for a in added:
156 aa = repo.wread(a)
156 aa = repo.wread(a)
157 bestscore, bestname = None, None
157 bestscore, bestname = None, None
158 for r in removed:
158 for r in removed:
159 rr = repo.file(r).read(mf[r])
159 rr = repo.file(r).read(mf[r])
160 delta = mdiff.textdiff(aa, rr)
160 delta = mdiff.textdiff(aa, rr)
161 if len(delta) < len(aa):
161 if len(delta) < len(aa):
162 myscore = 1.0 - (float(len(delta)) / len(aa))
162 myscore = 1.0 - (float(len(delta)) / len(aa))
163 if bestscore is None or myscore > bestscore:
163 if bestscore is None or myscore > bestscore:
164 bestscore, bestname = myscore, r
164 bestscore, bestname = myscore, r
165 if bestname and bestscore >= threshold:
165 if bestname and bestscore >= threshold:
166 yield bestname, a, bestscore
166 yield bestname, a, bestscore
167
167
168 def addremove(repo, pats=[], opts={}, wlock=None, dry_run=None,
168 def addremove(repo, pats=[], opts={}, wlock=None, dry_run=None,
169 similarity=None):
169 similarity=None):
170 if dry_run is None:
170 if dry_run is None:
171 dry_run = opts.get('dry_run')
171 dry_run = opts.get('dry_run')
172 if similarity is None:
172 if similarity is None:
173 similarity = float(opts.get('similarity') or 0)
173 similarity = float(opts.get('similarity') or 0)
174 add, remove = [], []
174 add, remove = [], []
175 mapping = {}
175 mapping = {}
176 for src, abs, rel, exact in walk(repo, pats, opts):
176 for src, abs, rel, exact in walk(repo, pats, opts):
177 if src == 'f' and repo.dirstate.state(abs) == '?':
177 if src == 'f' and repo.dirstate.state(abs) == '?':
178 add.append(abs)
178 add.append(abs)
179 mapping[abs] = rel, exact
179 mapping[abs] = rel, exact
180 if repo.ui.verbose or not exact:
180 if repo.ui.verbose or not exact:
181 repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
181 repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
182 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
182 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
183 remove.append(abs)
183 remove.append(abs)
184 mapping[abs] = rel, exact
184 mapping[abs] = rel, exact
185 if repo.ui.verbose or not exact:
185 if repo.ui.verbose or not exact:
186 repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
186 repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
187 if not dry_run:
187 if not dry_run:
188 repo.add(add, wlock=wlock)
188 repo.add(add, wlock=wlock)
189 repo.remove(remove, wlock=wlock)
189 repo.remove(remove, wlock=wlock)
190 if similarity > 0:
190 if similarity > 0:
191 for old, new, score in findrenames(repo, add, remove, similarity):
191 for old, new, score in findrenames(repo, add, remove, similarity):
192 oldrel, oldexact = mapping[old]
192 oldrel, oldexact = mapping[old]
193 newrel, newexact = mapping[new]
193 newrel, newexact = mapping[new]
194 if repo.ui.verbose or not oldexact or not newexact:
194 if repo.ui.verbose or not oldexact or not newexact:
195 repo.ui.status(_('recording removal of %s as rename to %s '
195 repo.ui.status(_('recording removal of %s as rename to %s '
196 '(%d%% similar)\n') %
196 '(%d%% similar)\n') %
197 (oldrel, newrel, score * 100))
197 (oldrel, newrel, score * 100))
198 if not dry_run:
198 if not dry_run:
199 repo.copy(old, new, wlock=wlock)
199 repo.copy(old, new, wlock=wlock)
200
200
201 class changeset_printer(object):
201 class changeset_printer(object):
202 '''show changeset information when templating not requested.'''
202 '''show changeset information when templating not requested.'''
203
203
204 def __init__(self, ui, repo, patch, brinfo, buffered):
204 def __init__(self, ui, repo, patch, brinfo, buffered):
205 self.ui = ui
205 self.ui = ui
206 self.repo = repo
206 self.repo = repo
207 self.buffered = buffered
207 self.buffered = buffered
208 self.patch = patch
208 self.patch = patch
209 self.brinfo = brinfo
209 self.brinfo = brinfo
210 self.header = {}
210 self.header = {}
211 self.hunk = {}
211 self.hunk = {}
212 self.lastheader = None
212 self.lastheader = None
213
213
214 def flush(self, rev):
214 def flush(self, rev):
215 if rev in self.header:
215 if rev in self.header:
216 h = self.header[rev]
216 h = self.header[rev]
217 if h != self.lastheader:
217 if h != self.lastheader:
218 self.lastheader = h
218 self.lastheader = h
219 self.ui.write(h)
219 self.ui.write(h)
220 del self.header[rev]
220 del self.header[rev]
221 if rev in self.hunk:
221 if rev in self.hunk:
222 self.ui.write(self.hunk[rev])
222 self.ui.write(self.hunk[rev])
223 del self.hunk[rev]
223 del self.hunk[rev]
224 return 1
224 return 1
225 return 0
225 return 0
226
226
227 def show(self, rev=0, changenode=None, copies=None, **props):
227 def show(self, rev=0, changenode=None, copies=(), **props):
228 if self.buffered:
228 if self.buffered:
229 self.ui.pushbuffer()
229 self.ui.pushbuffer()
230 self._show(rev, changenode, copies, props)
230 self._show(rev, changenode, copies, props)
231 self.hunk[rev] = self.ui.popbuffer()
231 self.hunk[rev] = self.ui.popbuffer()
232 else:
232 else:
233 self._show(rev, changenode, copies, props)
233 self._show(rev, changenode, copies, props)
234
234
235 def _show(self, rev, changenode, copies, props):
235 def _show(self, rev, changenode, copies, props):
236 '''show a single changeset or file revision'''
236 '''show a single changeset or file revision'''
237 log = self.repo.changelog
237 log = self.repo.changelog
238 if changenode is None:
238 if changenode is None:
239 changenode = log.node(rev)
239 changenode = log.node(rev)
240 elif not rev:
240 elif not rev:
241 rev = log.rev(changenode)
241 rev = log.rev(changenode)
242
242
243 if self.ui.quiet:
243 if self.ui.quiet:
244 self.ui.write("%d:%s\n" % (rev, short(changenode)))
244 self.ui.write("%d:%s\n" % (rev, short(changenode)))
245 return
245 return
246
246
247 changes = log.read(changenode)
247 changes = log.read(changenode)
248 date = util.datestr(changes[2])
248 date = util.datestr(changes[2])
249 extra = changes[5]
249 extra = changes[5]
250 branch = extra.get("branch")
250 branch = extra.get("branch")
251
251
252 hexfunc = self.ui.debugflag and hex or short
252 hexfunc = self.ui.debugflag and hex or short
253
253
254 parents = log.parentrevs(rev)
254 parents = log.parentrevs(rev)
255 if not self.ui.debugflag:
255 if not self.ui.debugflag:
256 if parents[1] == nullrev:
256 if parents[1] == nullrev:
257 if parents[0] >= rev - 1:
257 if parents[0] >= rev - 1:
258 parents = []
258 parents = []
259 else:
259 else:
260 parents = [parents[0]]
260 parents = [parents[0]]
261 parents = [(p, hexfunc(log.node(p))) for p in parents]
261 parents = [(p, hexfunc(log.node(p))) for p in parents]
262
262
263 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)))
263 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)))
264
264
265 # don't show the default branch name
265 # don't show the default branch name
266 if branch != 'default':
266 if branch != 'default':
267 branch = util.tolocal(branch)
267 branch = util.tolocal(branch)
268 self.ui.write(_("branch: %s\n") % branch)
268 self.ui.write(_("branch: %s\n") % branch)
269 for tag in self.repo.nodetags(changenode):
269 for tag in self.repo.nodetags(changenode):
270 self.ui.write(_("tag: %s\n") % tag)
270 self.ui.write(_("tag: %s\n") % tag)
271 for parent in parents:
271 for parent in parents:
272 self.ui.write(_("parent: %d:%s\n") % parent)
272 self.ui.write(_("parent: %d:%s\n") % parent)
273
273
274 if self.brinfo:
274 if self.brinfo:
275 br = self.repo.branchlookup([changenode])
275 br = self.repo.branchlookup([changenode])
276 if br:
276 if br:
277 self.ui.write(_("branch: %s\n") % " ".join(br[changenode]))
277 self.ui.write(_("branch: %s\n") % " ".join(br[changenode]))
278
278
279 if self.ui.debugflag:
279 if self.ui.debugflag:
280 self.ui.write(_("manifest: %d:%s\n") %
280 self.ui.write(_("manifest: %d:%s\n") %
281 (self.repo.manifest.rev(changes[0]), hex(changes[0])))
281 (self.repo.manifest.rev(changes[0]), hex(changes[0])))
282 self.ui.write(_("user: %s\n") % changes[1])
282 self.ui.write(_("user: %s\n") % changes[1])
283 self.ui.write(_("date: %s\n") % date)
283 self.ui.write(_("date: %s\n") % date)
284
284
285 if self.ui.debugflag:
285 if self.ui.debugflag:
286 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
286 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
287 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
287 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
288 files):
288 files):
289 if value:
289 if value:
290 self.ui.write("%-12s %s\n" % (key, " ".join(value)))
290 self.ui.write("%-12s %s\n" % (key, " ".join(value)))
291 elif changes[3] and self.ui.verbose:
291 elif changes[3] and self.ui.verbose:
292 self.ui.write(_("files: %s\n") % " ".join(changes[3]))
292 self.ui.write(_("files: %s\n") % " ".join(changes[3]))
293 if copies and self.ui.verbose:
293 if copies and self.ui.verbose:
294 copies = ['%s (%s)' % c for c in copies]
294 copies = ['%s (%s)' % c for c in copies]
295 self.ui.write(_("copies: %s\n") % ' '.join(copies))
295 self.ui.write(_("copies: %s\n") % ' '.join(copies))
296
296
297 if extra and self.ui.debugflag:
297 if extra and self.ui.debugflag:
298 extraitems = extra.items()
298 extraitems = extra.items()
299 extraitems.sort()
299 extraitems.sort()
300 for key, value in extraitems:
300 for key, value in extraitems:
301 self.ui.write(_("extra: %s=%s\n")
301 self.ui.write(_("extra: %s=%s\n")
302 % (key, value.encode('string_escape')))
302 % (key, value.encode('string_escape')))
303
303
304 description = changes[4].strip()
304 description = changes[4].strip()
305 if description:
305 if description:
306 if self.ui.verbose:
306 if self.ui.verbose:
307 self.ui.write(_("description:\n"))
307 self.ui.write(_("description:\n"))
308 self.ui.write(description)
308 self.ui.write(description)
309 self.ui.write("\n\n")
309 self.ui.write("\n\n")
310 else:
310 else:
311 self.ui.write(_("summary: %s\n") %
311 self.ui.write(_("summary: %s\n") %
312 description.splitlines()[0])
312 description.splitlines()[0])
313 self.ui.write("\n")
313 self.ui.write("\n")
314
314
315 self.showpatch(changenode)
315 self.showpatch(changenode)
316
316
317 def showpatch(self, node):
317 def showpatch(self, node):
318 if self.patch:
318 if self.patch:
319 prev = self.repo.changelog.parents(node)[0]
319 prev = self.repo.changelog.parents(node)[0]
320 patch.diff(self.repo, prev, node, match=self.patch, fp=self.ui)
320 patch.diff(self.repo, prev, node, match=self.patch, fp=self.ui)
321 self.ui.write("\n")
321 self.ui.write("\n")
322
322
323 class changeset_templater(changeset_printer):
323 class changeset_templater(changeset_printer):
324 '''format changeset information.'''
324 '''format changeset information.'''
325
325
326 def __init__(self, ui, repo, patch, brinfo, mapfile, buffered):
326 def __init__(self, ui, repo, patch, brinfo, mapfile, buffered):
327 changeset_printer.__init__(self, ui, repo, patch, brinfo, buffered)
327 changeset_printer.__init__(self, ui, repo, patch, brinfo, buffered)
328 self.t = templater.templater(mapfile, templater.common_filters,
328 self.t = templater.templater(mapfile, templater.common_filters,
329 cache={'parent': '{rev}:{node|short} ',
329 cache={'parent': '{rev}:{node|short} ',
330 'manifest': '{rev}:{node|short}',
330 'manifest': '{rev}:{node|short}',
331 'filecopy': '{name} ({source})'})
331 'filecopy': '{name} ({source})'})
332
332
333 def use_template(self, t):
333 def use_template(self, t):
334 '''set template string to use'''
334 '''set template string to use'''
335 self.t.cache['changeset'] = t
335 self.t.cache['changeset'] = t
336
336
337 def _show(self, rev, changenode, copies, props):
337 def _show(self, rev, changenode, copies, props):
338 '''show a single changeset or file revision'''
338 '''show a single changeset or file revision'''
339 log = self.repo.changelog
339 log = self.repo.changelog
340 if changenode is None:
340 if changenode is None:
341 changenode = log.node(rev)
341 changenode = log.node(rev)
342 elif not rev:
342 elif not rev:
343 rev = log.rev(changenode)
343 rev = log.rev(changenode)
344
344
345 changes = log.read(changenode)
345 changes = log.read(changenode)
346
346
347 def showlist(name, values, plural=None, **args):
347 def showlist(name, values, plural=None, **args):
348 '''expand set of values.
348 '''expand set of values.
349 name is name of key in template map.
349 name is name of key in template map.
350 values is list of strings or dicts.
350 values is list of strings or dicts.
351 plural is plural of name, if not simply name + 's'.
351 plural is plural of name, if not simply name + 's'.
352
352
353 expansion works like this, given name 'foo'.
353 expansion works like this, given name 'foo'.
354
354
355 if values is empty, expand 'no_foos'.
355 if values is empty, expand 'no_foos'.
356
356
357 if 'foo' not in template map, return values as a string,
357 if 'foo' not in template map, return values as a string,
358 joined by space.
358 joined by space.
359
359
360 expand 'start_foos'.
360 expand 'start_foos'.
361
361
362 for each value, expand 'foo'. if 'last_foo' in template
362 for each value, expand 'foo'. if 'last_foo' in template
363 map, expand it instead of 'foo' for last key.
363 map, expand it instead of 'foo' for last key.
364
364
365 expand 'end_foos'.
365 expand 'end_foos'.
366 '''
366 '''
367 if plural: names = plural
367 if plural: names = plural
368 else: names = name + 's'
368 else: names = name + 's'
369 if not values:
369 if not values:
370 noname = 'no_' + names
370 noname = 'no_' + names
371 if noname in self.t:
371 if noname in self.t:
372 yield self.t(noname, **args)
372 yield self.t(noname, **args)
373 return
373 return
374 if name not in self.t:
374 if name not in self.t:
375 if isinstance(values[0], str):
375 if isinstance(values[0], str):
376 yield ' '.join(values)
376 yield ' '.join(values)
377 else:
377 else:
378 for v in values:
378 for v in values:
379 yield dict(v, **args)
379 yield dict(v, **args)
380 return
380 return
381 startname = 'start_' + names
381 startname = 'start_' + names
382 if startname in self.t:
382 if startname in self.t:
383 yield self.t(startname, **args)
383 yield self.t(startname, **args)
384 vargs = args.copy()
384 vargs = args.copy()
385 def one(v, tag=name):
385 def one(v, tag=name):
386 try:
386 try:
387 vargs.update(v)
387 vargs.update(v)
388 except (AttributeError, ValueError):
388 except (AttributeError, ValueError):
389 try:
389 try:
390 for a, b in v:
390 for a, b in v:
391 vargs[a] = b
391 vargs[a] = b
392 except ValueError:
392 except ValueError:
393 vargs[name] = v
393 vargs[name] = v
394 return self.t(tag, **vargs)
394 return self.t(tag, **vargs)
395 lastname = 'last_' + name
395 lastname = 'last_' + name
396 if lastname in self.t:
396 if lastname in self.t:
397 last = values.pop()
397 last = values.pop()
398 else:
398 else:
399 last = None
399 last = None
400 for v in values:
400 for v in values:
401 yield one(v)
401 yield one(v)
402 if last is not None:
402 if last is not None:
403 yield one(last, tag=lastname)
403 yield one(last, tag=lastname)
404 endname = 'end_' + names
404 endname = 'end_' + names
405 if endname in self.t:
405 if endname in self.t:
406 yield self.t(endname, **args)
406 yield self.t(endname, **args)
407
407
408 def showbranches(**args):
408 def showbranches(**args):
409 branch = changes[5].get("branch")
409 branch = changes[5].get("branch")
410 if branch != 'default':
410 if branch != 'default':
411 branch = util.tolocal(branch)
411 branch = util.tolocal(branch)
412 return showlist('branch', [branch], plural='branches', **args)
412 return showlist('branch', [branch], plural='branches', **args)
413 # add old style branches if requested
413 # add old style branches if requested
414 if self.brinfo:
414 if self.brinfo:
415 br = self.repo.branchlookup([changenode])
415 br = self.repo.branchlookup([changenode])
416 if changenode in br:
416 if changenode in br:
417 return showlist('branch', br[changenode],
417 return showlist('branch', br[changenode],
418 plural='branches', **args)
418 plural='branches', **args)
419
419
420 def showparents(**args):
420 def showparents(**args):
421 parents = [[('rev', log.rev(p)), ('node', hex(p))]
421 parents = [[('rev', log.rev(p)), ('node', hex(p))]
422 for p in log.parents(changenode)
422 for p in log.parents(changenode)
423 if self.ui.debugflag or p != nullid]
423 if self.ui.debugflag or p != nullid]
424 if (not self.ui.debugflag and len(parents) == 1 and
424 if (not self.ui.debugflag and len(parents) == 1 and
425 parents[0][0][1] == rev - 1):
425 parents[0][0][1] == rev - 1):
426 return
426 return
427 return showlist('parent', parents, **args)
427 return showlist('parent', parents, **args)
428
428
429 def showtags(**args):
429 def showtags(**args):
430 return showlist('tag', self.repo.nodetags(changenode), **args)
430 return showlist('tag', self.repo.nodetags(changenode), **args)
431
431
432 def showextras(**args):
432 def showextras(**args):
433 extras = changes[5].items()
433 extras = changes[5].items()
434 extras.sort()
434 extras.sort()
435 for key, value in extras:
435 for key, value in extras:
436 args = args.copy()
436 args = args.copy()
437 args.update(dict(key=key, value=value))
437 args.update(dict(key=key, value=value))
438 yield self.t('extra', **args)
438 yield self.t('extra', **args)
439
439
440 def showcopies(**args):
440 def showcopies(**args):
441 c = [{'name': x[0], 'source': x[1]} for x in copies]
441 c = [{'name': x[0], 'source': x[1]} for x in copies]
442 return showlist('file_copy', c, plural='file_copies', **args)
442 return showlist('file_copy', c, plural='file_copies', **args)
443
443
444 if self.ui.debugflag:
444 if self.ui.debugflag:
445 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
445 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
446 def showfiles(**args):
446 def showfiles(**args):
447 return showlist('file', files[0], **args)
447 return showlist('file', files[0], **args)
448 def showadds(**args):
448 def showadds(**args):
449 return showlist('file_add', files[1], **args)
449 return showlist('file_add', files[1], **args)
450 def showdels(**args):
450 def showdels(**args):
451 return showlist('file_del', files[2], **args)
451 return showlist('file_del', files[2], **args)
452 def showmanifest(**args):
452 def showmanifest(**args):
453 args = args.copy()
453 args = args.copy()
454 args.update(dict(rev=self.repo.manifest.rev(changes[0]),
454 args.update(dict(rev=self.repo.manifest.rev(changes[0]),
455 node=hex(changes[0])))
455 node=hex(changes[0])))
456 return self.t('manifest', **args)
456 return self.t('manifest', **args)
457 else:
457 else:
458 def showfiles(**args):
458 def showfiles(**args):
459 return showlist('file', changes[3], **args)
459 return showlist('file', changes[3], **args)
460 showadds = ''
460 showadds = ''
461 showdels = ''
461 showdels = ''
462 showmanifest = ''
462 showmanifest = ''
463
463
464 defprops = {
464 defprops = {
465 'author': changes[1],
465 'author': changes[1],
466 'branches': showbranches,
466 'branches': showbranches,
467 'date': changes[2],
467 'date': changes[2],
468 'desc': changes[4],
468 'desc': changes[4],
469 'file_adds': showadds,
469 'file_adds': showadds,
470 'file_dels': showdels,
470 'file_dels': showdels,
471 'files': showfiles,
471 'files': showfiles,
472 'file_copies': showcopies,
472 'file_copies': showcopies,
473 'manifest': showmanifest,
473 'manifest': showmanifest,
474 'node': hex(changenode),
474 'node': hex(changenode),
475 'parents': showparents,
475 'parents': showparents,
476 'rev': rev,
476 'rev': rev,
477 'tags': showtags,
477 'tags': showtags,
478 'extras': showextras,
478 'extras': showextras,
479 }
479 }
480 props = props.copy()
480 props = props.copy()
481 props.update(defprops)
481 props.update(defprops)
482
482
483 try:
483 try:
484 if self.ui.debugflag and 'header_debug' in self.t:
484 if self.ui.debugflag and 'header_debug' in self.t:
485 key = 'header_debug'
485 key = 'header_debug'
486 elif self.ui.quiet and 'header_quiet' in self.t:
486 elif self.ui.quiet and 'header_quiet' in self.t:
487 key = 'header_quiet'
487 key = 'header_quiet'
488 elif self.ui.verbose and 'header_verbose' in self.t:
488 elif self.ui.verbose and 'header_verbose' in self.t:
489 key = 'header_verbose'
489 key = 'header_verbose'
490 elif 'header' in self.t:
490 elif 'header' in self.t:
491 key = 'header'
491 key = 'header'
492 else:
492 else:
493 key = ''
493 key = ''
494 if key:
494 if key:
495 h = templater.stringify(self.t(key, **props))
495 h = templater.stringify(self.t(key, **props))
496 if self.buffered:
496 if self.buffered:
497 self.header[rev] = h
497 self.header[rev] = h
498 else:
498 else:
499 self.ui.write(h)
499 self.ui.write(h)
500 if self.ui.debugflag and 'changeset_debug' in self.t:
500 if self.ui.debugflag and 'changeset_debug' in self.t:
501 key = 'changeset_debug'
501 key = 'changeset_debug'
502 elif self.ui.quiet and 'changeset_quiet' in self.t:
502 elif self.ui.quiet and 'changeset_quiet' in self.t:
503 key = 'changeset_quiet'
503 key = 'changeset_quiet'
504 elif self.ui.verbose and 'changeset_verbose' in self.t:
504 elif self.ui.verbose and 'changeset_verbose' in self.t:
505 key = 'changeset_verbose'
505 key = 'changeset_verbose'
506 else:
506 else:
507 key = 'changeset'
507 key = 'changeset'
508 self.ui.write(templater.stringify(self.t(key, **props)))
508 self.ui.write(templater.stringify(self.t(key, **props)))
509 self.showpatch(changenode)
509 self.showpatch(changenode)
510 except KeyError, inst:
510 except KeyError, inst:
511 raise util.Abort(_("%s: no key named '%s'") % (self.t.mapfile,
511 raise util.Abort(_("%s: no key named '%s'") % (self.t.mapfile,
512 inst.args[0]))
512 inst.args[0]))
513 except SyntaxError, inst:
513 except SyntaxError, inst:
514 raise util.Abort(_('%s: %s') % (self.t.mapfile, inst.args[0]))
514 raise util.Abort(_('%s: %s') % (self.t.mapfile, inst.args[0]))
515
515
516 def show_changeset(ui, repo, opts, buffered=False, matchfn=False):
516 def show_changeset(ui, repo, opts, buffered=False, matchfn=False):
517 """show one changeset using template or regular display.
517 """show one changeset using template or regular display.
518
518
519 Display format will be the first non-empty hit of:
519 Display format will be the first non-empty hit of:
520 1. option 'template'
520 1. option 'template'
521 2. option 'style'
521 2. option 'style'
522 3. [ui] setting 'logtemplate'
522 3. [ui] setting 'logtemplate'
523 4. [ui] setting 'style'
523 4. [ui] setting 'style'
524 If all of these values are either the unset or the empty string,
524 If all of these values are either the unset or the empty string,
525 regular display via changeset_printer() is done.
525 regular display via changeset_printer() is done.
526 """
526 """
527 # options
527 # options
528 patch = False
528 patch = False
529 if opts.get('patch'):
529 if opts.get('patch'):
530 patch = matchfn or util.always
530 patch = matchfn or util.always
531
531
532 br = None
532 br = None
533 if opts.get('branches'):
533 if opts.get('branches'):
534 ui.warn(_("the --branches option is deprecated, "
534 ui.warn(_("the --branches option is deprecated, "
535 "please use 'hg branches' instead\n"))
535 "please use 'hg branches' instead\n"))
536 br = True
536 br = True
537 tmpl = opts.get('template')
537 tmpl = opts.get('template')
538 mapfile = None
538 mapfile = None
539 if tmpl:
539 if tmpl:
540 tmpl = templater.parsestring(tmpl, quoted=False)
540 tmpl = templater.parsestring(tmpl, quoted=False)
541 else:
541 else:
542 mapfile = opts.get('style')
542 mapfile = opts.get('style')
543 # ui settings
543 # ui settings
544 if not mapfile:
544 if not mapfile:
545 tmpl = ui.config('ui', 'logtemplate')
545 tmpl = ui.config('ui', 'logtemplate')
546 if tmpl:
546 if tmpl:
547 tmpl = templater.parsestring(tmpl)
547 tmpl = templater.parsestring(tmpl)
548 else:
548 else:
549 mapfile = ui.config('ui', 'style')
549 mapfile = ui.config('ui', 'style')
550
550
551 if tmpl or mapfile:
551 if tmpl or mapfile:
552 if mapfile:
552 if mapfile:
553 if not os.path.split(mapfile)[0]:
553 if not os.path.split(mapfile)[0]:
554 mapname = (templater.templatepath('map-cmdline.' + mapfile)
554 mapname = (templater.templatepath('map-cmdline.' + mapfile)
555 or templater.templatepath(mapfile))
555 or templater.templatepath(mapfile))
556 if mapname: mapfile = mapname
556 if mapname: mapfile = mapname
557 try:
557 try:
558 t = changeset_templater(ui, repo, patch, br, mapfile, buffered)
558 t = changeset_templater(ui, repo, patch, br, mapfile, buffered)
559 except SyntaxError, inst:
559 except SyntaxError, inst:
560 raise util.Abort(inst.args[0])
560 raise util.Abort(inst.args[0])
561 if tmpl: t.use_template(tmpl)
561 if tmpl: t.use_template(tmpl)
562 return t
562 return t
563 return changeset_printer(ui, repo, patch, br, buffered)
563 return changeset_printer(ui, repo, patch, br, buffered)
564
564
565 def finddate(ui, repo, date):
565 def finddate(ui, repo, date):
566 """Find the tipmost changeset that matches the given date spec"""
566 """Find the tipmost changeset that matches the given date spec"""
567 df = util.matchdate(date + " to " + date)
567 df = util.matchdate(date + " to " + date)
568 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
568 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
569 changeiter, matchfn = walkchangerevs(ui, repo, [], get, {'rev':None})
569 changeiter, matchfn = walkchangerevs(ui, repo, [], get, {'rev':None})
570 results = {}
570 results = {}
571 for st, rev, fns in changeiter:
571 for st, rev, fns in changeiter:
572 if st == 'add':
572 if st == 'add':
573 d = get(rev)[2]
573 d = get(rev)[2]
574 if df(d[0]):
574 if df(d[0]):
575 results[rev] = d
575 results[rev] = d
576 elif st == 'iter':
576 elif st == 'iter':
577 if rev in results:
577 if rev in results:
578 ui.status("Found revision %s from %s\n" %
578 ui.status("Found revision %s from %s\n" %
579 (rev, util.datestr(results[rev])))
579 (rev, util.datestr(results[rev])))
580 return str(rev)
580 return str(rev)
581
581
582 raise util.Abort(_("revision matching date not found"))
582 raise util.Abort(_("revision matching date not found"))
583
583
584 def walkchangerevs(ui, repo, pats, change, opts):
584 def walkchangerevs(ui, repo, pats, change, opts):
585 '''Iterate over files and the revs they changed in.
585 '''Iterate over files and the revs they changed in.
586
586
587 Callers most commonly need to iterate backwards over the history
587 Callers most commonly need to iterate backwards over the history
588 it is interested in. Doing so has awful (quadratic-looking)
588 it is interested in. Doing so has awful (quadratic-looking)
589 performance, so we use iterators in a "windowed" way.
589 performance, so we use iterators in a "windowed" way.
590
590
591 We walk a window of revisions in the desired order. Within the
591 We walk a window of revisions in the desired order. Within the
592 window, we first walk forwards to gather data, then in the desired
592 window, we first walk forwards to gather data, then in the desired
593 order (usually backwards) to display it.
593 order (usually backwards) to display it.
594
594
595 This function returns an (iterator, matchfn) tuple. The iterator
595 This function returns an (iterator, matchfn) tuple. The iterator
596 yields 3-tuples. They will be of one of the following forms:
596 yields 3-tuples. They will be of one of the following forms:
597
597
598 "window", incrementing, lastrev: stepping through a window,
598 "window", incrementing, lastrev: stepping through a window,
599 positive if walking forwards through revs, last rev in the
599 positive if walking forwards through revs, last rev in the
600 sequence iterated over - use to reset state for the current window
600 sequence iterated over - use to reset state for the current window
601
601
602 "add", rev, fns: out-of-order traversal of the given file names
602 "add", rev, fns: out-of-order traversal of the given file names
603 fns, which changed during revision rev - use to gather data for
603 fns, which changed during revision rev - use to gather data for
604 possible display
604 possible display
605
605
606 "iter", rev, None: in-order traversal of the revs earlier iterated
606 "iter", rev, None: in-order traversal of the revs earlier iterated
607 over with "add" - use to display data'''
607 over with "add" - use to display data'''
608
608
609 def increasing_windows(start, end, windowsize=8, sizelimit=512):
609 def increasing_windows(start, end, windowsize=8, sizelimit=512):
610 if start < end:
610 if start < end:
611 while start < end:
611 while start < end:
612 yield start, min(windowsize, end-start)
612 yield start, min(windowsize, end-start)
613 start += windowsize
613 start += windowsize
614 if windowsize < sizelimit:
614 if windowsize < sizelimit:
615 windowsize *= 2
615 windowsize *= 2
616 else:
616 else:
617 while start > end:
617 while start > end:
618 yield start, min(windowsize, start-end-1)
618 yield start, min(windowsize, start-end-1)
619 start -= windowsize
619 start -= windowsize
620 if windowsize < sizelimit:
620 if windowsize < sizelimit:
621 windowsize *= 2
621 windowsize *= 2
622
622
623 files, matchfn, anypats = matchpats(repo, pats, opts)
623 files, matchfn, anypats = matchpats(repo, pats, opts)
624 follow = opts.get('follow') or opts.get('follow_first')
624 follow = opts.get('follow') or opts.get('follow_first')
625
625
626 if repo.changelog.count() == 0:
626 if repo.changelog.count() == 0:
627 return [], matchfn
627 return [], matchfn
628
628
629 if follow:
629 if follow:
630 defrange = '%s:0' % repo.changectx().rev()
630 defrange = '%s:0' % repo.changectx().rev()
631 else:
631 else:
632 defrange = 'tip:0'
632 defrange = 'tip:0'
633 revs = revrange(repo, opts['rev'] or [defrange])
633 revs = revrange(repo, opts['rev'] or [defrange])
634 wanted = {}
634 wanted = {}
635 slowpath = anypats or opts.get('removed')
635 slowpath = anypats or opts.get('removed')
636 fncache = {}
636 fncache = {}
637
637
638 if not slowpath and not files:
638 if not slowpath and not files:
639 # No files, no patterns. Display all revs.
639 # No files, no patterns. Display all revs.
640 wanted = dict.fromkeys(revs)
640 wanted = dict.fromkeys(revs)
641 copies = []
641 copies = []
642 if not slowpath:
642 if not slowpath:
643 # Only files, no patterns. Check the history of each file.
643 # Only files, no patterns. Check the history of each file.
644 def filerevgen(filelog, node):
644 def filerevgen(filelog, node):
645 cl_count = repo.changelog.count()
645 cl_count = repo.changelog.count()
646 if node is None:
646 if node is None:
647 last = filelog.count() - 1
647 last = filelog.count() - 1
648 else:
648 else:
649 last = filelog.rev(node)
649 last = filelog.rev(node)
650 for i, window in increasing_windows(last, nullrev):
650 for i, window in increasing_windows(last, nullrev):
651 revs = []
651 revs = []
652 for j in xrange(i - window, i + 1):
652 for j in xrange(i - window, i + 1):
653 n = filelog.node(j)
653 n = filelog.node(j)
654 revs.append((filelog.linkrev(n),
654 revs.append((filelog.linkrev(n),
655 follow and filelog.renamed(n)))
655 follow and filelog.renamed(n)))
656 revs.reverse()
656 revs.reverse()
657 for rev in revs:
657 for rev in revs:
658 # only yield rev for which we have the changelog, it can
658 # only yield rev for which we have the changelog, it can
659 # happen while doing "hg log" during a pull or commit
659 # happen while doing "hg log" during a pull or commit
660 if rev[0] < cl_count:
660 if rev[0] < cl_count:
661 yield rev
661 yield rev
662 def iterfiles():
662 def iterfiles():
663 for filename in files:
663 for filename in files:
664 yield filename, None
664 yield filename, None
665 for filename_node in copies:
665 for filename_node in copies:
666 yield filename_node
666 yield filename_node
667 minrev, maxrev = min(revs), max(revs)
667 minrev, maxrev = min(revs), max(revs)
668 for file_, node in iterfiles():
668 for file_, node in iterfiles():
669 filelog = repo.file(file_)
669 filelog = repo.file(file_)
670 # A zero count may be a directory or deleted file, so
670 # A zero count may be a directory or deleted file, so
671 # try to find matching entries on the slow path.
671 # try to find matching entries on the slow path.
672 if filelog.count() == 0:
672 if filelog.count() == 0:
673 slowpath = True
673 slowpath = True
674 break
674 break
675 for rev, copied in filerevgen(filelog, node):
675 for rev, copied in filerevgen(filelog, node):
676 if rev <= maxrev:
676 if rev <= maxrev:
677 if rev < minrev:
677 if rev < minrev:
678 break
678 break
679 fncache.setdefault(rev, [])
679 fncache.setdefault(rev, [])
680 fncache[rev].append(file_)
680 fncache[rev].append(file_)
681 wanted[rev] = 1
681 wanted[rev] = 1
682 if follow and copied:
682 if follow and copied:
683 copies.append(copied)
683 copies.append(copied)
684 if slowpath:
684 if slowpath:
685 if follow:
685 if follow:
686 raise util.Abort(_('can only follow copies/renames for explicit '
686 raise util.Abort(_('can only follow copies/renames for explicit '
687 'file names'))
687 'file names'))
688
688
689 # The slow path checks files modified in every changeset.
689 # The slow path checks files modified in every changeset.
690 def changerevgen():
690 def changerevgen():
691 for i, window in increasing_windows(repo.changelog.count()-1,
691 for i, window in increasing_windows(repo.changelog.count()-1,
692 nullrev):
692 nullrev):
693 for j in xrange(i - window, i + 1):
693 for j in xrange(i - window, i + 1):
694 yield j, change(j)[3]
694 yield j, change(j)[3]
695
695
696 for rev, changefiles in changerevgen():
696 for rev, changefiles in changerevgen():
697 matches = filter(matchfn, changefiles)
697 matches = filter(matchfn, changefiles)
698 if matches:
698 if matches:
699 fncache[rev] = matches
699 fncache[rev] = matches
700 wanted[rev] = 1
700 wanted[rev] = 1
701
701
702 class followfilter:
702 class followfilter:
703 def __init__(self, onlyfirst=False):
703 def __init__(self, onlyfirst=False):
704 self.startrev = nullrev
704 self.startrev = nullrev
705 self.roots = []
705 self.roots = []
706 self.onlyfirst = onlyfirst
706 self.onlyfirst = onlyfirst
707
707
708 def match(self, rev):
708 def match(self, rev):
709 def realparents(rev):
709 def realparents(rev):
710 if self.onlyfirst:
710 if self.onlyfirst:
711 return repo.changelog.parentrevs(rev)[0:1]
711 return repo.changelog.parentrevs(rev)[0:1]
712 else:
712 else:
713 return filter(lambda x: x != nullrev,
713 return filter(lambda x: x != nullrev,
714 repo.changelog.parentrevs(rev))
714 repo.changelog.parentrevs(rev))
715
715
716 if self.startrev == nullrev:
716 if self.startrev == nullrev:
717 self.startrev = rev
717 self.startrev = rev
718 return True
718 return True
719
719
720 if rev > self.startrev:
720 if rev > self.startrev:
721 # forward: all descendants
721 # forward: all descendants
722 if not self.roots:
722 if not self.roots:
723 self.roots.append(self.startrev)
723 self.roots.append(self.startrev)
724 for parent in realparents(rev):
724 for parent in realparents(rev):
725 if parent in self.roots:
725 if parent in self.roots:
726 self.roots.append(rev)
726 self.roots.append(rev)
727 return True
727 return True
728 else:
728 else:
729 # backwards: all parents
729 # backwards: all parents
730 if not self.roots:
730 if not self.roots:
731 self.roots.extend(realparents(self.startrev))
731 self.roots.extend(realparents(self.startrev))
732 if rev in self.roots:
732 if rev in self.roots:
733 self.roots.remove(rev)
733 self.roots.remove(rev)
734 self.roots.extend(realparents(rev))
734 self.roots.extend(realparents(rev))
735 return True
735 return True
736
736
737 return False
737 return False
738
738
739 # it might be worthwhile to do this in the iterator if the rev range
739 # it might be worthwhile to do this in the iterator if the rev range
740 # is descending and the prune args are all within that range
740 # is descending and the prune args are all within that range
741 for rev in opts.get('prune', ()):
741 for rev in opts.get('prune', ()):
742 rev = repo.changelog.rev(repo.lookup(rev))
742 rev = repo.changelog.rev(repo.lookup(rev))
743 ff = followfilter()
743 ff = followfilter()
744 stop = min(revs[0], revs[-1])
744 stop = min(revs[0], revs[-1])
745 for x in xrange(rev, stop-1, -1):
745 for x in xrange(rev, stop-1, -1):
746 if ff.match(x) and x in wanted:
746 if ff.match(x) and x in wanted:
747 del wanted[x]
747 del wanted[x]
748
748
749 def iterate():
749 def iterate():
750 if follow and not files:
750 if follow and not files:
751 ff = followfilter(onlyfirst=opts.get('follow_first'))
751 ff = followfilter(onlyfirst=opts.get('follow_first'))
752 def want(rev):
752 def want(rev):
753 if ff.match(rev) and rev in wanted:
753 if ff.match(rev) and rev in wanted:
754 return True
754 return True
755 return False
755 return False
756 else:
756 else:
757 def want(rev):
757 def want(rev):
758 return rev in wanted
758 return rev in wanted
759
759
760 for i, window in increasing_windows(0, len(revs)):
760 for i, window in increasing_windows(0, len(revs)):
761 yield 'window', revs[0] < revs[-1], revs[-1]
761 yield 'window', revs[0] < revs[-1], revs[-1]
762 nrevs = [rev for rev in revs[i:i+window] if want(rev)]
762 nrevs = [rev for rev in revs[i:i+window] if want(rev)]
763 srevs = list(nrevs)
763 srevs = list(nrevs)
764 srevs.sort()
764 srevs.sort()
765 for rev in srevs:
765 for rev in srevs:
766 fns = fncache.get(rev)
766 fns = fncache.get(rev)
767 if not fns:
767 if not fns:
768 def fns_generator():
768 def fns_generator():
769 for f in change(rev)[3]:
769 for f in change(rev)[3]:
770 if matchfn(f):
770 if matchfn(f):
771 yield f
771 yield f
772 fns = fns_generator()
772 fns = fns_generator()
773 yield 'add', rev, fns
773 yield 'add', rev, fns
774 for rev in nrevs:
774 for rev in nrevs:
775 yield 'iter', rev, None
775 yield 'iter', rev, None
776 return iterate(), matchfn
776 return iterate(), matchfn
@@ -1,100 +1,103 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
22
23 # make sure user/global hgrc does not affect tests
23 # make sure user/global hgrc does not affect tests
24 echo '[ui]' > .hg/hgrc
24 echo '[ui]' > .hg/hgrc
25 echo 'logtemplate =' >> .hg/hgrc
25 echo 'logtemplate =' >> .hg/hgrc
26 echo 'style =' >> .hg/hgrc
26 echo 'style =' >> .hg/hgrc
27
27
28 echo '# default style is like normal output'
28 echo '# default style is like normal output'
29 echo '# normal'
29 echo '# normal'
30 hg log > log.out
30 hg log > log.out
31 hg log --style default > style.out
31 hg log --style default > style.out
32 diff log.out style.out
32 diff log.out style.out
33 echo '# verbose'
33 echo '# verbose'
34 hg log -v > log.out
34 hg log -v > log.out
35 hg log -v --style default > style.out
35 hg log -v --style default > style.out
36 diff log.out style.out
36 diff log.out style.out
37 echo '# debug'
37 echo '# debug'
38 hg log --debug > log.out
38 hg log --debug > log.out
39 hg log --debug --style default > style.out
39 hg log --debug --style default > style.out
40 diff log.out style.out
40 diff log.out style.out
41
41
42 echo '# revision with no copies (used to print a traceback)'
43 hg tip -v --template '\n'
44
42 echo '# compact style works'
45 echo '# compact style works'
43 hg log --style compact
46 hg log --style compact
44 hg log -v --style compact
47 hg log -v --style compact
45 hg log --debug --style compact
48 hg log --debug --style compact
46
49
47 echo '# error if style not readable'
50 echo '# error if style not readable'
48 touch q
51 touch q
49 chmod 0 q
52 chmod 0 q
50 hg log --style ./q
53 hg log --style ./q
51
54
52 echo '# error if no style'
55 echo '# error if no style'
53 hg log --style notexist
56 hg log --style notexist
54
57
55 echo '# error if style missing key'
58 echo '# error if style missing key'
56 echo 'q = q' > t
59 echo 'q = q' > t
57 hg log --style ./t
60 hg log --style ./t
58
61
59 echo '# error if include fails'
62 echo '# error if include fails'
60 echo 'changeset = q' >> t
63 echo 'changeset = q' >> t
61 hg log --style ./t
64 hg log --style ./t
62
65
63 echo '# include works'
66 echo '# include works'
64 rm q
67 rm q
65 echo '{rev}' > q
68 echo '{rev}' > q
66 hg log --style ./t
69 hg log --style ./t
67
70
68 echo '# ui.style works'
71 echo '# ui.style works'
69 echo '[ui]' > .hg/hgrc
72 echo '[ui]' > .hg/hgrc
70 echo 'style = t' >> .hg/hgrc
73 echo 'style = t' >> .hg/hgrc
71 hg log
74 hg log
72
75
73 echo '# issue338'
76 echo '# issue338'
74 hg log --style=changelog > changelog
77 hg log --style=changelog > changelog
75 cat changelog
78 cat changelog
76
79
77 echo "# keys work"
80 echo "# keys work"
78 for key in author branches date desc file_adds file_dels files \
81 for key in author branches date desc file_adds file_dels files \
79 manifest node parents rev tags; do
82 manifest node parents rev tags; do
80 for mode in '' --verbose --debug; do
83 for mode in '' --verbose --debug; do
81 hg log $mode --template "$key$mode: {$key}\n"
84 hg log $mode --template "$key$mode: {$key}\n"
82 done
85 done
83 done
86 done
84
87
85 echo '# filters work'
88 echo '# filters work'
86 hg log --template '{author|domain}\n'
89 hg log --template '{author|domain}\n'
87 hg log --template '{author|person}\n'
90 hg log --template '{author|person}\n'
88 hg log --template '{author|user}\n'
91 hg log --template '{author|user}\n'
89 hg log --template '{date|age}\n' > /dev/null || exit 1
92 hg log --template '{date|age}\n' > /dev/null || exit 1
90 hg log --template '{date|date}\n'
93 hg log --template '{date|date}\n'
91 hg log --template '{date|isodate}\n'
94 hg log --template '{date|isodate}\n'
92 hg log --template '{date|rfc822date}\n'
95 hg log --template '{date|rfc822date}\n'
93 hg log --template '{desc|firstline}\n'
96 hg log --template '{desc|firstline}\n'
94 hg log --template '{node|short}\n'
97 hg log --template '{node|short}\n'
95
98
96 echo '# error on syntax'
99 echo '# error on syntax'
97 echo 'x = "f' >> t
100 echo 'x = "f' >> t
98 hg log
101 hg log
99
102
100 echo '# done'
103 echo '# done'
@@ -1,339 +1,341 b''
1 # default style is like normal output
1 # default style is like normal output
2 # normal
2 # normal
3 # verbose
3 # verbose
4 # debug
4 # debug
5 # revision with no copies (used to print a traceback)
6
5 # compact style works
7 # compact style works
6 4[tip] 32a18f097fcc 1970-01-17 04:53 +0000 person
8 4[tip] 32a18f097fcc 1970-01-17 04:53 +0000 person
7 new branch
9 new branch
8
10
9 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
11 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
10 no user, no domain
12 no user, no domain
11
13
12 2 97054abb4ab8 1970-01-14 21:20 +0000 other
14 2 97054abb4ab8 1970-01-14 21:20 +0000 other
13 no person
15 no person
14
16
15 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
17 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
16 other 1
18 other 1
17
19
18 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
20 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
19 line 1
21 line 1
20
22
21 4[tip] 32a18f097fcc 1970-01-17 04:53 +0000 person
23 4[tip] 32a18f097fcc 1970-01-17 04:53 +0000 person
22 new branch
24 new branch
23
25
24 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
26 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
25 no user, no domain
27 no user, no domain
26
28
27 2 97054abb4ab8 1970-01-14 21:20 +0000 other
29 2 97054abb4ab8 1970-01-14 21:20 +0000 other
28 no person
30 no person
29
31
30 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
32 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
31 other 1
33 other 1
32
34
33 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
35 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
34 line 1
36 line 1
35
37
36 4[tip]:3,-1 32a18f097fcc 1970-01-17 04:53 +0000 person
38 4[tip]:3,-1 32a18f097fcc 1970-01-17 04:53 +0000 person
37 new branch
39 new branch
38
40
39 3:2,-1 10e46f2dcbf4 1970-01-16 01:06 +0000 person
41 3:2,-1 10e46f2dcbf4 1970-01-16 01:06 +0000 person
40 no user, no domain
42 no user, no domain
41
43
42 2:1,-1 97054abb4ab8 1970-01-14 21:20 +0000 other
44 2:1,-1 97054abb4ab8 1970-01-14 21:20 +0000 other
43 no person
45 no person
44
46
45 1:0,-1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
47 1:0,-1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
46 other 1
48 other 1
47
49
48 0:-1,-1 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
50 0:-1,-1 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
49 line 1
51 line 1
50
52
51 # error if style not readable
53 # error if style not readable
52 abort: Permission denied: ./q
54 abort: Permission denied: ./q
53 # error if no style
55 # error if no style
54 abort: No such file or directory: notexist
56 abort: No such file or directory: notexist
55 # error if style missing key
57 # error if style missing key
56 abort: ./t: no key named 'changeset'
58 abort: ./t: no key named 'changeset'
57 # error if include fails
59 # error if include fails
58 abort: template file ./q: Permission denied
60 abort: template file ./q: Permission denied
59 # include works
61 # include works
60 4
62 4
61 3
63 3
62 2
64 2
63 1
65 1
64 0
66 0
65 # ui.style works
67 # ui.style works
66 4
68 4
67 3
69 3
68 2
70 2
69 1
71 1
70 0
72 0
71 # issue338
73 # issue338
72 1970-01-17 person <person>
74 1970-01-17 person <person>
73
75
74 * new branch
76 * new branch
75 [32a18f097fcc] [tip]
77 [32a18f097fcc] [tip]
76
78
77 1970-01-16 person <person>
79 1970-01-16 person <person>
78
80
79 * c:
81 * c:
80 no user, no domain
82 no user, no domain
81 [10e46f2dcbf4]
83 [10e46f2dcbf4]
82
84
83 1970-01-14 other <other@place>
85 1970-01-14 other <other@place>
84
86
85 * c:
87 * c:
86 no person
88 no person
87 [97054abb4ab8]
89 [97054abb4ab8]
88
90
89 1970-01-13 A. N. Other <other@place>
91 1970-01-13 A. N. Other <other@place>
90
92
91 * b:
93 * b:
92 other 1 other 2
94 other 1 other 2
93
95
94 other 3
96 other 3
95 [b608e9d1a3f0]
97 [b608e9d1a3f0]
96
98
97 1970-01-12 User Name <user@hostname>
99 1970-01-12 User Name <user@hostname>
98
100
99 * a:
101 * a:
100 line 1 line 2
102 line 1 line 2
101 [1e4e1b8f71e0]
103 [1e4e1b8f71e0]
102
104
103 # keys work
105 # keys work
104 author: person
106 author: person
105 author: person
107 author: person
106 author: other@place
108 author: other@place
107 author: A. N. Other <other@place>
109 author: A. N. Other <other@place>
108 author: User Name <user@hostname>
110 author: User Name <user@hostname>
109 author--verbose: person
111 author--verbose: person
110 author--verbose: person
112 author--verbose: person
111 author--verbose: other@place
113 author--verbose: other@place
112 author--verbose: A. N. Other <other@place>
114 author--verbose: A. N. Other <other@place>
113 author--verbose: User Name <user@hostname>
115 author--verbose: User Name <user@hostname>
114 author--debug: person
116 author--debug: person
115 author--debug: person
117 author--debug: person
116 author--debug: other@place
118 author--debug: other@place
117 author--debug: A. N. Other <other@place>
119 author--debug: A. N. Other <other@place>
118 author--debug: User Name <user@hostname>
120 author--debug: User Name <user@hostname>
119 branches: foo
121 branches: foo
120 branches:
122 branches:
121 branches:
123 branches:
122 branches:
124 branches:
123 branches:
125 branches:
124 branches--verbose: foo
126 branches--verbose: foo
125 branches--verbose:
127 branches--verbose:
126 branches--verbose:
128 branches--verbose:
127 branches--verbose:
129 branches--verbose:
128 branches--verbose:
130 branches--verbose:
129 branches--debug: foo
131 branches--debug: foo
130 branches--debug:
132 branches--debug:
131 branches--debug:
133 branches--debug:
132 branches--debug:
134 branches--debug:
133 branches--debug:
135 branches--debug:
134 date: 1400000.00
136 date: 1400000.00
135 date: 1300000.00
137 date: 1300000.00
136 date: 1200000.00
138 date: 1200000.00
137 date: 1100000.00
139 date: 1100000.00
138 date: 1000000.00
140 date: 1000000.00
139 date--verbose: 1400000.00
141 date--verbose: 1400000.00
140 date--verbose: 1300000.00
142 date--verbose: 1300000.00
141 date--verbose: 1200000.00
143 date--verbose: 1200000.00
142 date--verbose: 1100000.00
144 date--verbose: 1100000.00
143 date--verbose: 1000000.00
145 date--verbose: 1000000.00
144 date--debug: 1400000.00
146 date--debug: 1400000.00
145 date--debug: 1300000.00
147 date--debug: 1300000.00
146 date--debug: 1200000.00
148 date--debug: 1200000.00
147 date--debug: 1100000.00
149 date--debug: 1100000.00
148 date--debug: 1000000.00
150 date--debug: 1000000.00
149 desc: new branch
151 desc: new branch
150 desc: no user, no domain
152 desc: no user, no domain
151 desc: no person
153 desc: no person
152 desc: other 1
154 desc: other 1
153 other 2
155 other 2
154
156
155 other 3
157 other 3
156 desc: line 1
158 desc: line 1
157 line 2
159 line 2
158 desc--verbose: new branch
160 desc--verbose: new branch
159 desc--verbose: no user, no domain
161 desc--verbose: no user, no domain
160 desc--verbose: no person
162 desc--verbose: no person
161 desc--verbose: other 1
163 desc--verbose: other 1
162 other 2
164 other 2
163
165
164 other 3
166 other 3
165 desc--verbose: line 1
167 desc--verbose: line 1
166 line 2
168 line 2
167 desc--debug: new branch
169 desc--debug: new branch
168 desc--debug: no user, no domain
170 desc--debug: no user, no domain
169 desc--debug: no person
171 desc--debug: no person
170 desc--debug: other 1
172 desc--debug: other 1
171 other 2
173 other 2
172
174
173 other 3
175 other 3
174 desc--debug: line 1
176 desc--debug: line 1
175 line 2
177 line 2
176 file_adds:
178 file_adds:
177 file_adds:
179 file_adds:
178 file_adds:
180 file_adds:
179 file_adds:
181 file_adds:
180 file_adds:
182 file_adds:
181 file_adds--verbose:
183 file_adds--verbose:
182 file_adds--verbose:
184 file_adds--verbose:
183 file_adds--verbose:
185 file_adds--verbose:
184 file_adds--verbose:
186 file_adds--verbose:
185 file_adds--verbose:
187 file_adds--verbose:
186 file_adds--debug:
188 file_adds--debug:
187 file_adds--debug:
189 file_adds--debug:
188 file_adds--debug: c
190 file_adds--debug: c
189 file_adds--debug: b
191 file_adds--debug: b
190 file_adds--debug: a
192 file_adds--debug: a
191 file_dels:
193 file_dels:
192 file_dels:
194 file_dels:
193 file_dels:
195 file_dels:
194 file_dels:
196 file_dels:
195 file_dels:
197 file_dels:
196 file_dels--verbose:
198 file_dels--verbose:
197 file_dels--verbose:
199 file_dels--verbose:
198 file_dels--verbose:
200 file_dels--verbose:
199 file_dels--verbose:
201 file_dels--verbose:
200 file_dels--verbose:
202 file_dels--verbose:
201 file_dels--debug:
203 file_dels--debug:
202 file_dels--debug:
204 file_dels--debug:
203 file_dels--debug:
205 file_dels--debug:
204 file_dels--debug:
206 file_dels--debug:
205 file_dels--debug:
207 file_dels--debug:
206 files:
208 files:
207 files: c
209 files: c
208 files: c
210 files: c
209 files: b
211 files: b
210 files: a
212 files: a
211 files--verbose:
213 files--verbose:
212 files--verbose: c
214 files--verbose: c
213 files--verbose: c
215 files--verbose: c
214 files--verbose: b
216 files--verbose: b
215 files--verbose: a
217 files--verbose: a
216 files--debug:
218 files--debug:
217 files--debug: c
219 files--debug: c
218 files--debug:
220 files--debug:
219 files--debug:
221 files--debug:
220 files--debug:
222 files--debug:
221 manifest:
223 manifest:
222 manifest:
224 manifest:
223 manifest:
225 manifest:
224 manifest:
226 manifest:
225 manifest:
227 manifest:
226 manifest--verbose:
228 manifest--verbose:
227 manifest--verbose:
229 manifest--verbose:
228 manifest--verbose:
230 manifest--verbose:
229 manifest--verbose:
231 manifest--verbose:
230 manifest--verbose:
232 manifest--verbose:
231 manifest--debug: 4:90ae8dda64e1
233 manifest--debug: 4:90ae8dda64e1
232 manifest--debug: 3:cb5a1327723b
234 manifest--debug: 3:cb5a1327723b
233 manifest--debug: 2:6e0e82995c35
235 manifest--debug: 2:6e0e82995c35
234 manifest--debug: 1:4e8d705b1e53
236 manifest--debug: 1:4e8d705b1e53
235 manifest--debug: 0:a0c8bcbbb45c
237 manifest--debug: 0:a0c8bcbbb45c
236 node: 32a18f097fcccf76ef282f62f8a85b3adf8d13c4
238 node: 32a18f097fcccf76ef282f62f8a85b3adf8d13c4
237 node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
239 node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
238 node: 97054abb4ab824450e9164180baf491ae0078465
240 node: 97054abb4ab824450e9164180baf491ae0078465
239 node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
241 node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
240 node: 1e4e1b8f71e05681d422154f5421e385fec3454f
242 node: 1e4e1b8f71e05681d422154f5421e385fec3454f
241 node--verbose: 32a18f097fcccf76ef282f62f8a85b3adf8d13c4
243 node--verbose: 32a18f097fcccf76ef282f62f8a85b3adf8d13c4
242 node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
244 node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
243 node--verbose: 97054abb4ab824450e9164180baf491ae0078465
245 node--verbose: 97054abb4ab824450e9164180baf491ae0078465
244 node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
246 node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
245 node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
247 node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
246 node--debug: 32a18f097fcccf76ef282f62f8a85b3adf8d13c4
248 node--debug: 32a18f097fcccf76ef282f62f8a85b3adf8d13c4
247 node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
249 node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
248 node--debug: 97054abb4ab824450e9164180baf491ae0078465
250 node--debug: 97054abb4ab824450e9164180baf491ae0078465
249 node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
251 node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
250 node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
252 node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
251 parents:
253 parents:
252 parents:
254 parents:
253 parents:
255 parents:
254 parents:
256 parents:
255 parents:
257 parents:
256 parents--verbose:
258 parents--verbose:
257 parents--verbose:
259 parents--verbose:
258 parents--verbose:
260 parents--verbose:
259 parents--verbose:
261 parents--verbose:
260 parents--verbose:
262 parents--verbose:
261 parents--debug: 3:10e46f2dcbf4 -1:000000000000
263 parents--debug: 3:10e46f2dcbf4 -1:000000000000
262 parents--debug: 2:97054abb4ab8 -1:000000000000
264 parents--debug: 2:97054abb4ab8 -1:000000000000
263 parents--debug: 1:b608e9d1a3f0 -1:000000000000
265 parents--debug: 1:b608e9d1a3f0 -1:000000000000
264 parents--debug: 0:1e4e1b8f71e0 -1:000000000000
266 parents--debug: 0:1e4e1b8f71e0 -1:000000000000
265 parents--debug: -1:000000000000 -1:000000000000
267 parents--debug: -1:000000000000 -1:000000000000
266 rev: 4
268 rev: 4
267 rev: 3
269 rev: 3
268 rev: 2
270 rev: 2
269 rev: 1
271 rev: 1
270 rev: 0
272 rev: 0
271 rev--verbose: 4
273 rev--verbose: 4
272 rev--verbose: 3
274 rev--verbose: 3
273 rev--verbose: 2
275 rev--verbose: 2
274 rev--verbose: 1
276 rev--verbose: 1
275 rev--verbose: 0
277 rev--verbose: 0
276 rev--debug: 4
278 rev--debug: 4
277 rev--debug: 3
279 rev--debug: 3
278 rev--debug: 2
280 rev--debug: 2
279 rev--debug: 1
281 rev--debug: 1
280 rev--debug: 0
282 rev--debug: 0
281 tags: tip
283 tags: tip
282 tags:
284 tags:
283 tags:
285 tags:
284 tags:
286 tags:
285 tags:
287 tags:
286 tags--verbose: tip
288 tags--verbose: tip
287 tags--verbose:
289 tags--verbose:
288 tags--verbose:
290 tags--verbose:
289 tags--verbose:
291 tags--verbose:
290 tags--verbose:
292 tags--verbose:
291 tags--debug: tip
293 tags--debug: tip
292 tags--debug:
294 tags--debug:
293 tags--debug:
295 tags--debug:
294 tags--debug:
296 tags--debug:
295 tags--debug:
297 tags--debug:
296 # filters work
298 # filters work
297
299
298
300
299 place
301 place
300 place
302 place
301 hostname
303 hostname
302 person
304 person
303 person
305 person
304 other
306 other
305 A. N. Other
307 A. N. Other
306 User Name
308 User Name
307 person
309 person
308 person
310 person
309 other
311 other
310 other
312 other
311 user
313 user
312 Sat Jan 17 04:53:20 1970 +0000
314 Sat Jan 17 04:53:20 1970 +0000
313 Fri Jan 16 01:06:40 1970 +0000
315 Fri Jan 16 01:06:40 1970 +0000
314 Wed Jan 14 21:20:00 1970 +0000
316 Wed Jan 14 21:20:00 1970 +0000
315 Tue Jan 13 17:33:20 1970 +0000
317 Tue Jan 13 17:33:20 1970 +0000
316 Mon Jan 12 13:46:40 1970 +0000
318 Mon Jan 12 13:46:40 1970 +0000
317 1970-01-17 04:53 +0000
319 1970-01-17 04:53 +0000
318 1970-01-16 01:06 +0000
320 1970-01-16 01:06 +0000
319 1970-01-14 21:20 +0000
321 1970-01-14 21:20 +0000
320 1970-01-13 17:33 +0000
322 1970-01-13 17:33 +0000
321 1970-01-12 13:46 +0000
323 1970-01-12 13:46 +0000
322 Sat, 17 Jan 1970 04:53:20 +0000
324 Sat, 17 Jan 1970 04:53:20 +0000
323 Fri, 16 Jan 1970 01:06:40 +0000
325 Fri, 16 Jan 1970 01:06:40 +0000
324 Wed, 14 Jan 1970 21:20:00 +0000
326 Wed, 14 Jan 1970 21:20:00 +0000
325 Tue, 13 Jan 1970 17:33:20 +0000
327 Tue, 13 Jan 1970 17:33:20 +0000
326 Mon, 12 Jan 1970 13:46:40 +0000
328 Mon, 12 Jan 1970 13:46:40 +0000
327 new branch
329 new branch
328 no user, no domain
330 no user, no domain
329 no person
331 no person
330 other 1
332 other 1
331 line 1
333 line 1
332 32a18f097fcc
334 32a18f097fcc
333 10e46f2dcbf4
335 10e46f2dcbf4
334 97054abb4ab8
336 97054abb4ab8
335 b608e9d1a3f0
337 b608e9d1a3f0
336 1e4e1b8f71e0
338 1e4e1b8f71e0
337 # error on syntax
339 # error on syntax
338 abort: t:3: unmatched quotes
340 abort: t:3: unmatched quotes
339 # done
341 # done
General Comments 0
You need to be logged in to leave comments. Login now