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