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