##// END OF EJS Templates
churn: count lines that look like diff headers but are not...
Aay Jay Chan -
r47158:b84c3d43 default
parent child Browse files
Show More
@@ -1,259 +1,264 b''
1 # churn.py - create a graph of revisions count grouped by template
1 # churn.py - create a graph of revisions count grouped by template
2 #
2 #
3 # Copyright 2006 Josef "Jeff" Sipek <jeffpc@josefsipek.net>
3 # Copyright 2006 Josef "Jeff" Sipek <jeffpc@josefsipek.net>
4 # Copyright 2008 Alexander Solovyov <piranha@piranha.org.ua>
4 # Copyright 2008 Alexander Solovyov <piranha@piranha.org.ua>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 '''command to display statistics about repository history'''
9 '''command to display statistics about repository history'''
10
10
11 from __future__ import absolute_import, division
11 from __future__ import absolute_import, division
12
12
13 import datetime
13 import datetime
14 import os
14 import os
15 import time
15 import time
16
16
17 from mercurial.i18n import _
17 from mercurial.i18n import _
18 from mercurial.pycompat import open
18 from mercurial.pycompat import open
19 from mercurial import (
19 from mercurial import (
20 cmdutil,
20 cmdutil,
21 encoding,
21 encoding,
22 logcmdutil,
22 logcmdutil,
23 patch,
23 patch,
24 pycompat,
24 pycompat,
25 registrar,
25 registrar,
26 scmutil,
26 scmutil,
27 )
27 )
28
28
29 cmdtable = {}
29 cmdtable = {}
30 command = registrar.command(cmdtable)
30 command = registrar.command(cmdtable)
31 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
31 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
32 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
32 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
33 # be specifying the version(s) of Mercurial they are tested with, or
33 # be specifying the version(s) of Mercurial they are tested with, or
34 # leave the attribute unspecified.
34 # leave the attribute unspecified.
35 testedwith = b'ships-with-hg-core'
35 testedwith = b'ships-with-hg-core'
36
36
37
37
38 def changedlines(ui, repo, ctx1, ctx2, fmatch):
38 def changedlines(ui, repo, ctx1, ctx2, fmatch):
39 added, removed = 0, 0
39 added, removed = 0, 0
40 diff = b''.join(patch.diff(repo, ctx1.node(), ctx2.node(), fmatch))
40 diff = b''.join(patch.diff(repo, ctx1.node(), ctx2.node(), fmatch))
41 inhunk = False
41 for l in diff.split(b'\n'):
42 for l in diff.split(b'\n'):
42 if l.startswith(b"+") and not l.startswith(b"+++ "):
43 if inhunk and l.startswith(b"+"):
43 added += 1
44 added += 1
44 elif l.startswith(b"-") and not l.startswith(b"--- "):
45 elif inhunk and l.startswith(b"-"):
45 removed += 1
46 removed += 1
47 elif l.startswith(b"@"):
48 inhunk = True
49 elif l.startswith(b"d"):
50 inhunk = False
46 return (added, removed)
51 return (added, removed)
47
52
48
53
49 def countrate(ui, repo, amap, *pats, **opts):
54 def countrate(ui, repo, amap, *pats, **opts):
50 """Calculate stats"""
55 """Calculate stats"""
51 opts = pycompat.byteskwargs(opts)
56 opts = pycompat.byteskwargs(opts)
52 if opts.get(b'dateformat'):
57 if opts.get(b'dateformat'):
53
58
54 def getkey(ctx):
59 def getkey(ctx):
55 t, tz = ctx.date()
60 t, tz = ctx.date()
56 date = datetime.datetime(*time.gmtime(float(t) - tz)[:6])
61 date = datetime.datetime(*time.gmtime(float(t) - tz)[:6])
57 return encoding.strtolocal(
62 return encoding.strtolocal(
58 date.strftime(encoding.strfromlocal(opts[b'dateformat']))
63 date.strftime(encoding.strfromlocal(opts[b'dateformat']))
59 )
64 )
60
65
61 else:
66 else:
62 tmpl = opts.get(b'oldtemplate') or opts.get(b'template')
67 tmpl = opts.get(b'oldtemplate') or opts.get(b'template')
63 tmpl = logcmdutil.maketemplater(ui, repo, tmpl)
68 tmpl = logcmdutil.maketemplater(ui, repo, tmpl)
64
69
65 def getkey(ctx):
70 def getkey(ctx):
66 ui.pushbuffer()
71 ui.pushbuffer()
67 tmpl.show(ctx)
72 tmpl.show(ctx)
68 return ui.popbuffer()
73 return ui.popbuffer()
69
74
70 progress = ui.makeprogress(
75 progress = ui.makeprogress(
71 _(b'analyzing'), unit=_(b'revisions'), total=len(repo)
76 _(b'analyzing'), unit=_(b'revisions'), total=len(repo)
72 )
77 )
73 rate = {}
78 rate = {}
74
79
75 def prep(ctx, fmatch):
80 def prep(ctx, fmatch):
76 rev = ctx.rev()
81 rev = ctx.rev()
77 key = getkey(ctx).strip()
82 key = getkey(ctx).strip()
78 key = amap.get(key, key) # alias remap
83 key = amap.get(key, key) # alias remap
79 if opts.get(b'changesets'):
84 if opts.get(b'changesets'):
80 rate[key] = (rate.get(key, (0,))[0] + 1, 0)
85 rate[key] = (rate.get(key, (0,))[0] + 1, 0)
81 else:
86 else:
82 parents = ctx.parents()
87 parents = ctx.parents()
83 if len(parents) > 1:
88 if len(parents) > 1:
84 ui.note(_(b'revision %d is a merge, ignoring...\n') % (rev,))
89 ui.note(_(b'revision %d is a merge, ignoring...\n') % (rev,))
85 return
90 return
86
91
87 ctx1 = parents[0]
92 ctx1 = parents[0]
88 lines = changedlines(ui, repo, ctx1, ctx, fmatch)
93 lines = changedlines(ui, repo, ctx1, ctx, fmatch)
89 rate[key] = [r + l for r, l in zip(rate.get(key, (0, 0)), lines)]
94 rate[key] = [r + l for r, l in zip(rate.get(key, (0, 0)), lines)]
90
95
91 progress.increment()
96 progress.increment()
92
97
93 wopts = logcmdutil.walkopts(
98 wopts = logcmdutil.walkopts(
94 pats=pats,
99 pats=pats,
95 opts=opts,
100 opts=opts,
96 revspec=opts[b'rev'],
101 revspec=opts[b'rev'],
97 date=opts[b'date'],
102 date=opts[b'date'],
98 include_pats=opts[b'include'],
103 include_pats=opts[b'include'],
99 exclude_pats=opts[b'exclude'],
104 exclude_pats=opts[b'exclude'],
100 )
105 )
101 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
106 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
102 for ctx in scmutil.walkchangerevs(repo, revs, makefilematcher, prep):
107 for ctx in scmutil.walkchangerevs(repo, revs, makefilematcher, prep):
103 continue
108 continue
104
109
105 progress.complete()
110 progress.complete()
106
111
107 return rate
112 return rate
108
113
109
114
110 @command(
115 @command(
111 b'churn',
116 b'churn',
112 [
117 [
113 (
118 (
114 b'r',
119 b'r',
115 b'rev',
120 b'rev',
116 [],
121 [],
117 _(b'count rate for the specified revision or revset'),
122 _(b'count rate for the specified revision or revset'),
118 _(b'REV'),
123 _(b'REV'),
119 ),
124 ),
120 (
125 (
121 b'd',
126 b'd',
122 b'date',
127 b'date',
123 b'',
128 b'',
124 _(b'count rate for revisions matching date spec'),
129 _(b'count rate for revisions matching date spec'),
125 _(b'DATE'),
130 _(b'DATE'),
126 ),
131 ),
127 (
132 (
128 b't',
133 b't',
129 b'oldtemplate',
134 b'oldtemplate',
130 b'',
135 b'',
131 _(b'template to group changesets (DEPRECATED)'),
136 _(b'template to group changesets (DEPRECATED)'),
132 _(b'TEMPLATE'),
137 _(b'TEMPLATE'),
133 ),
138 ),
134 (
139 (
135 b'T',
140 b'T',
136 b'template',
141 b'template',
137 b'{author|email}',
142 b'{author|email}',
138 _(b'template to group changesets'),
143 _(b'template to group changesets'),
139 _(b'TEMPLATE'),
144 _(b'TEMPLATE'),
140 ),
145 ),
141 (
146 (
142 b'f',
147 b'f',
143 b'dateformat',
148 b'dateformat',
144 b'',
149 b'',
145 _(b'strftime-compatible format for grouping by date'),
150 _(b'strftime-compatible format for grouping by date'),
146 _(b'FORMAT'),
151 _(b'FORMAT'),
147 ),
152 ),
148 (b'c', b'changesets', False, _(b'count rate by number of changesets')),
153 (b'c', b'changesets', False, _(b'count rate by number of changesets')),
149 (b's', b'sort', False, _(b'sort by key (default: sort by count)')),
154 (b's', b'sort', False, _(b'sort by key (default: sort by count)')),
150 (b'', b'diffstat', False, _(b'display added/removed lines separately')),
155 (b'', b'diffstat', False, _(b'display added/removed lines separately')),
151 (b'', b'aliases', b'', _(b'file with email aliases'), _(b'FILE')),
156 (b'', b'aliases', b'', _(b'file with email aliases'), _(b'FILE')),
152 ]
157 ]
153 + cmdutil.walkopts,
158 + cmdutil.walkopts,
154 _(b"hg churn [-d DATE] [-r REV] [--aliases FILE] [FILE]"),
159 _(b"hg churn [-d DATE] [-r REV] [--aliases FILE] [FILE]"),
155 helpcategory=command.CATEGORY_MAINTENANCE,
160 helpcategory=command.CATEGORY_MAINTENANCE,
156 inferrepo=True,
161 inferrepo=True,
157 )
162 )
158 def churn(ui, repo, *pats, **opts):
163 def churn(ui, repo, *pats, **opts):
159 """histogram of changes to the repository
164 """histogram of changes to the repository
160
165
161 This command will display a histogram representing the number
166 This command will display a histogram representing the number
162 of changed lines or revisions, grouped according to the given
167 of changed lines or revisions, grouped according to the given
163 template. The default template will group changes by author.
168 template. The default template will group changes by author.
164 The --dateformat option may be used to group the results by
169 The --dateformat option may be used to group the results by
165 date instead.
170 date instead.
166
171
167 Statistics are based on the number of changed lines, or
172 Statistics are based on the number of changed lines, or
168 alternatively the number of matching revisions if the
173 alternatively the number of matching revisions if the
169 --changesets option is specified.
174 --changesets option is specified.
170
175
171 Examples::
176 Examples::
172
177
173 # display count of changed lines for every committer
178 # display count of changed lines for every committer
174 hg churn -T "{author|email}"
179 hg churn -T "{author|email}"
175
180
176 # display daily activity graph
181 # display daily activity graph
177 hg churn -f "%H" -s -c
182 hg churn -f "%H" -s -c
178
183
179 # display activity of developers by month
184 # display activity of developers by month
180 hg churn -f "%Y-%m" -s -c
185 hg churn -f "%Y-%m" -s -c
181
186
182 # display count of lines changed in every year
187 # display count of lines changed in every year
183 hg churn -f "%Y" -s
188 hg churn -f "%Y" -s
184
189
185 # display count of lines changed in a time range
190 # display count of lines changed in a time range
186 hg churn -d "2020-04 to 2020-09"
191 hg churn -d "2020-04 to 2020-09"
187
192
188 It is possible to map alternate email addresses to a main address
193 It is possible to map alternate email addresses to a main address
189 by providing a file using the following format::
194 by providing a file using the following format::
190
195
191 <alias email> = <actual email>
196 <alias email> = <actual email>
192
197
193 Such a file may be specified with the --aliases option, otherwise
198 Such a file may be specified with the --aliases option, otherwise
194 a .hgchurn file will be looked for in the working directory root.
199 a .hgchurn file will be looked for in the working directory root.
195 Aliases will be split from the rightmost "=".
200 Aliases will be split from the rightmost "=".
196 """
201 """
197
202
198 def pad(s, l):
203 def pad(s, l):
199 return s + b" " * (l - encoding.colwidth(s))
204 return s + b" " * (l - encoding.colwidth(s))
200
205
201 amap = {}
206 amap = {}
202 aliases = opts.get('aliases')
207 aliases = opts.get('aliases')
203 if not aliases and os.path.exists(repo.wjoin(b'.hgchurn')):
208 if not aliases and os.path.exists(repo.wjoin(b'.hgchurn')):
204 aliases = repo.wjoin(b'.hgchurn')
209 aliases = repo.wjoin(b'.hgchurn')
205 if aliases:
210 if aliases:
206 for l in open(aliases, b"rb"):
211 for l in open(aliases, b"rb"):
207 try:
212 try:
208 alias, actual = l.rsplit(b'=' in l and b'=' or None, 1)
213 alias, actual = l.rsplit(b'=' in l and b'=' or None, 1)
209 amap[alias.strip()] = actual.strip()
214 amap[alias.strip()] = actual.strip()
210 except ValueError:
215 except ValueError:
211 l = l.strip()
216 l = l.strip()
212 if l:
217 if l:
213 ui.warn(_(b"skipping malformed alias: %s\n") % l)
218 ui.warn(_(b"skipping malformed alias: %s\n") % l)
214 continue
219 continue
215
220
216 rate = list(countrate(ui, repo, amap, *pats, **opts).items())
221 rate = list(countrate(ui, repo, amap, *pats, **opts).items())
217 if not rate:
222 if not rate:
218 return
223 return
219
224
220 if opts.get('sort'):
225 if opts.get('sort'):
221 rate.sort()
226 rate.sort()
222 else:
227 else:
223 rate.sort(key=lambda x: (-sum(x[1]), x))
228 rate.sort(key=lambda x: (-sum(x[1]), x))
224
229
225 # Be careful not to have a zero maxcount (issue833)
230 # Be careful not to have a zero maxcount (issue833)
226 maxcount = float(max(sum(v) for k, v in rate)) or 1.0
231 maxcount = float(max(sum(v) for k, v in rate)) or 1.0
227 maxname = max(len(k) for k, v in rate)
232 maxname = max(len(k) for k, v in rate)
228
233
229 ttywidth = ui.termwidth()
234 ttywidth = ui.termwidth()
230 ui.debug(b"assuming %i character terminal\n" % ttywidth)
235 ui.debug(b"assuming %i character terminal\n" % ttywidth)
231 width = ttywidth - maxname - 2 - 2 - 2
236 width = ttywidth - maxname - 2 - 2 - 2
232
237
233 if opts.get('diffstat'):
238 if opts.get('diffstat'):
234 width -= 15
239 width -= 15
235
240
236 def format(name, diffstat):
241 def format(name, diffstat):
237 added, removed = diffstat
242 added, removed = diffstat
238 return b"%s %15s %s%s\n" % (
243 return b"%s %15s %s%s\n" % (
239 pad(name, maxname),
244 pad(name, maxname),
240 b'+%d/-%d' % (added, removed),
245 b'+%d/-%d' % (added, removed),
241 ui.label(b'+' * charnum(added), b'diffstat.inserted'),
246 ui.label(b'+' * charnum(added), b'diffstat.inserted'),
242 ui.label(b'-' * charnum(removed), b'diffstat.deleted'),
247 ui.label(b'-' * charnum(removed), b'diffstat.deleted'),
243 )
248 )
244
249
245 else:
250 else:
246 width -= 6
251 width -= 6
247
252
248 def format(name, count):
253 def format(name, count):
249 return b"%s %6d %s\n" % (
254 return b"%s %6d %s\n" % (
250 pad(name, maxname),
255 pad(name, maxname),
251 sum(count),
256 sum(count),
252 b'*' * charnum(sum(count)),
257 b'*' * charnum(sum(count)),
253 )
258 )
254
259
255 def charnum(count):
260 def charnum(count):
256 return int(count * width // maxcount)
261 return int(count * width // maxcount)
257
262
258 for name, count in rate:
263 for name, count in rate:
259 ui.write(format(name, count))
264 ui.write(format(name, count))
@@ -1,197 +1,216 b''
1 $ echo "[extensions]" >> $HGRCPATH
1 $ echo "[extensions]" >> $HGRCPATH
2 $ echo "churn=" >> $HGRCPATH
2 $ echo "churn=" >> $HGRCPATH
3
3
4 create test repository
4 create test repository
5
5
6 $ hg init repo
6 $ hg init repo
7 $ cd repo
7 $ cd repo
8 $ echo a > a
8 $ echo a > a
9 $ hg ci -Am adda -u user1 -d 6:00
9 $ hg ci -Am adda -u user1 -d 6:00
10 adding a
10 adding a
11 $ echo b >> a
11 $ echo b >> a
12 $ echo b > b
12 $ echo b > b
13 $ hg ci -m changeba -u user2 -d 9:00 a
13 $ hg ci -m changeba -u user2 -d 9:00 a
14 $ hg ci -Am addb -u user2 -d 9:30
14 $ hg ci -Am addb -u user2 -d 9:30
15 adding b
15 adding b
16 $ echo c >> a
16 $ echo c >> a
17 $ echo c >> b
17 $ echo c >> b
18 $ echo c > c
18 $ echo c > c
19 $ hg ci -m changeca -u user3 -d 12:00 a
19 $ hg ci -m changeca -u user3 -d 12:00 a
20 $ hg ci -m changecb -u user3 -d 12:15 b
20 $ hg ci -m changecb -u user3 -d 12:15 b
21 $ hg ci -Am addc -u user3 -d 12:30
21 $ hg ci -Am addc -u user3 -d 12:30
22 adding c
22 adding c
23 $ mkdir -p d/e
23 $ mkdir -p d/e
24 $ echo abc > d/e/f1.txt
24 $ echo abc > d/e/f1.txt
25 $ hg ci -Am "add d/e/f1.txt" -u user1 -d 12:45 d/e/f1.txt
25 $ hg ci -Am "add d/e/f1.txt" -u user1 -d 12:45 d/e/f1.txt
26 $ mkdir -p d/g
26 $ mkdir -p d/g
27 $ echo def > d/g/f2.txt
27 $ echo def > d/g/f2.txt
28 $ hg ci -Am "add d/g/f2.txt" -u user1 -d 13:00 d/g/f2.txt
28 $ hg ci -Am "add d/g/f2.txt" -u user1 -d 13:00 d/g/f2.txt
29
29
30
30
31 churn separate directories
31 churn separate directories
32
32
33 $ cd d
33 $ cd d
34 $ hg churn e
34 $ hg churn e
35 user1 1 ***************************************************************
35 user1 1 ***************************************************************
36
36
37 churn all
37 churn all
38
38
39 $ hg churn
39 $ hg churn
40 user1 3 ***************************************************************
40 user1 3 ***************************************************************
41 user3 3 ***************************************************************
41 user3 3 ***************************************************************
42 user2 2 ******************************************
42 user2 2 ******************************************
43
43
44 churn excluding one dir
44 churn excluding one dir
45
45
46 $ hg churn -X e
46 $ hg churn -X e
47 user3 3 ***************************************************************
47 user3 3 ***************************************************************
48 user1 2 ******************************************
48 user1 2 ******************************************
49 user2 2 ******************************************
49 user2 2 ******************************************
50
50
51 churn up to rev 2
51 churn up to rev 2
52
52
53 $ hg churn -r :2
53 $ hg churn -r :2
54 user2 2 ***************************************************************
54 user2 2 ***************************************************************
55 user1 1 *******************************
55 user1 1 *******************************
56 $ cd ..
56 $ cd ..
57
57
58 churn with aliases
58 churn with aliases
59
59
60 $ cat > ../aliases <<EOF
60 $ cat > ../aliases <<EOF
61 > user1 alias1
61 > user1 alias1
62 > user3 alias3
62 > user3 alias3
63 > not-an-alias
63 > not-an-alias
64 > EOF
64 > EOF
65
65
66 churn with .hgchurn
66 churn with .hgchurn
67
67
68 $ mv ../aliases .hgchurn
68 $ mv ../aliases .hgchurn
69 $ hg churn
69 $ hg churn
70 skipping malformed alias: not-an-alias
70 skipping malformed alias: not-an-alias
71 alias1 3 **************************************************************
71 alias1 3 **************************************************************
72 alias3 3 **************************************************************
72 alias3 3 **************************************************************
73 user2 2 *****************************************
73 user2 2 *****************************************
74 $ rm .hgchurn
74 $ rm .hgchurn
75
75
76 churn with column specifier
76 churn with column specifier
77
77
78 $ COLUMNS=40 hg churn
78 $ COLUMNS=40 hg churn
79 user1 3 ***********************
79 user1 3 ***********************
80 user3 3 ***********************
80 user3 3 ***********************
81 user2 2 ***************
81 user2 2 ***************
82
82
83 churn by hour
83 churn by hour
84
84
85 $ hg churn -f '%H' -s
85 $ hg churn -f '%H' -s
86 06 1 ****************
86 06 1 ****************
87 09 2 *********************************
87 09 2 *********************************
88 12 4 ******************************************************************
88 12 4 ******************************************************************
89 13 1 ****************
89 13 1 ****************
90
90
91
91
92 churn with separated added/removed lines
92 churn with separated added/removed lines
93
93
94 $ hg rm d/g/f2.txt
94 $ hg rm d/g/f2.txt
95 $ hg ci -Am "removed d/g/f2.txt" -u user1 -d 14:00 d/g/f2.txt
95 $ hg ci -Am "removed d/g/f2.txt" -u user1 -d 14:00 d/g/f2.txt
96 $ hg churn --diffstat
96 $ hg churn --diffstat
97 user1 +3/-1 ++++++++++++++++++++++++++++++++++++++++-------------
97 user1 +3/-1 ++++++++++++++++++++++++++++++++++++++++-------------
98 user3 +3/-0 ++++++++++++++++++++++++++++++++++++++++
98 user3 +3/-0 ++++++++++++++++++++++++++++++++++++++++
99 user2 +2/-0 +++++++++++++++++++++++++++
99 user2 +2/-0 +++++++++++++++++++++++++++
100
100
101 churn --diffstat with color
101 churn --diffstat with color
102
102
103 $ hg --config extensions.color= churn --config color.mode=ansi \
103 $ hg --config extensions.color= churn --config color.mode=ansi \
104 > --diffstat --color=always
104 > --diffstat --color=always
105 user1 +3/-1 \x1b[0;32m++++++++++++++++++++++++++++++++++++++++\x1b[0m\x1b[0;31m-------------\x1b[0m (esc)
105 user1 +3/-1 \x1b[0;32m++++++++++++++++++++++++++++++++++++++++\x1b[0m\x1b[0;31m-------------\x1b[0m (esc)
106 user3 +3/-0 \x1b[0;32m++++++++++++++++++++++++++++++++++++++++\x1b[0m (esc)
106 user3 +3/-0 \x1b[0;32m++++++++++++++++++++++++++++++++++++++++\x1b[0m (esc)
107 user2 +2/-0 \x1b[0;32m+++++++++++++++++++++++++++\x1b[0m (esc)
107 user2 +2/-0 \x1b[0;32m+++++++++++++++++++++++++++\x1b[0m (esc)
108
108
109
109
110 changeset number churn
110 changeset number churn
111
111
112 $ hg churn -c
112 $ hg churn -c
113 user1 4 ***************************************************************
113 user1 4 ***************************************************************
114 user3 3 ***********************************************
114 user3 3 ***********************************************
115 user2 2 *******************************
115 user2 2 *******************************
116
116
117 $ echo 'with space = no-space' >> ../aliases
117 $ echo 'with space = no-space' >> ../aliases
118 $ echo a >> a
118 $ echo a >> a
119 $ hg commit -m a -u 'with space' -d 15:00
119 $ hg commit -m a -u 'with space' -d 15:00
120
120
121 churn with space in alias
121 churn with space in alias
122
122
123 $ hg churn --aliases ../aliases -r tip
123 $ hg churn --aliases ../aliases -r tip
124 no-space 1 ************************************************************
124 no-space 1 ************************************************************
125
125
126 $ cd ..
126 $ cd ..
127
127
128
128
129 Issue833: ZeroDivisionError
129 Issue833: ZeroDivisionError
130
130
131 $ hg init issue-833
131 $ hg init issue-833
132 $ cd issue-833
132 $ cd issue-833
133 $ touch foo
133 $ touch foo
134 $ hg ci -Am foo
134 $ hg ci -Am foo
135 adding foo
135 adding foo
136
136
137 this was failing with a ZeroDivisionError
137 this was failing with a ZeroDivisionError
138
138
139 $ hg churn
139 $ hg churn
140 test 0
140 test 0
141 $ cd ..
141 $ cd ..
142
142
143 Ignore trailing or leading spaces in emails
143 Ignore trailing or leading spaces in emails
144
144
145 $ cd repo
145 $ cd repo
146 $ touch bar
146 $ touch bar
147 $ hg ci -Am'bar' -u 'user4 <user4@x.com>'
147 $ hg ci -Am'bar' -u 'user4 <user4@x.com>'
148 adding bar
148 adding bar
149 $ touch foo
149 $ touch foo
150 $ hg ci -Am'foo' -u 'user4 < user4@x.com >'
150 $ hg ci -Am'foo' -u 'user4 < user4@x.com >'
151 adding foo
151 adding foo
152 $ hg log -l2 --template '[{author|email}]\n'
152 $ hg log -l2 --template '[{author|email}]\n'
153 [ user4@x.com ]
153 [ user4@x.com ]
154 [user4@x.com]
154 [user4@x.com]
155 $ hg churn -c
155 $ hg churn -c
156 user1 4 *********************************************************
156 user1 4 *********************************************************
157 user3 3 ******************************************
157 user3 3 ******************************************
158 user2 2 ****************************
158 user2 2 ****************************
159 user4@x.com 2 ****************************
159 user4@x.com 2 ****************************
160 with space 1 **************
160 with space 1 **************
161
161
162 Test multibyte sequences in names
162 Test multibyte sequences in names
163
163
164 $ echo bar >> bar
164 $ echo bar >> bar
165 $ hg --encoding utf-8 ci -m'changed bar' -u 'El NiΓ±o <nino@x.com>'
165 $ hg --encoding utf-8 ci -m'changed bar' -u 'El NiΓ±o <nino@x.com>'
166 $ hg --encoding utf-8 churn -ct '{author|person}'
166 $ hg --encoding utf-8 churn -ct '{author|person}'
167 user1 4 **********************************************************
167 user1 4 **********************************************************
168 user3 3 *******************************************
168 user3 3 *******************************************
169 user2 2 *****************************
169 user2 2 *****************************
170 user4 2 *****************************
170 user4 2 *****************************
171 El Ni\xc3\xb1o 1 ************** (esc)
171 El Ni\xc3\xb1o 1 ************** (esc)
172 with space 1 **************
172 with space 1 **************
173
173
174 Test --template argument, with backwards compatibility
174 Test --template argument, with backwards compatibility
175
175
176 $ hg churn -t '{author|user}'
176 $ hg churn -t '{author|user}'
177 user1 4 ***************************************************************
177 user1 4 ***************************************************************
178 user3 3 ***********************************************
178 user3 3 ***********************************************
179 user2 2 *******************************
179 user2 2 *******************************
180 nino 1 ***************
180 nino 1 ***************
181 with 1 ***************
181 with 1 ***************
182 0
182 0
183 user4 0
183 user4 0
184 $ hg churn -T '{author|user}'
184 $ hg churn -T '{author|user}'
185 user1 4 ***************************************************************
185 user1 4 ***************************************************************
186 user3 3 ***********************************************
186 user3 3 ***********************************************
187 user2 2 *******************************
187 user2 2 *******************************
188 nino 1 ***************
188 nino 1 ***************
189 with 1 ***************
189 with 1 ***************
190 0
190 0
191 user4 0
191 user4 0
192 $ hg churn -t 'alltogether'
192 $ hg churn -t 'alltogether'
193 alltogether 11 *********************************************************
193 alltogether 11 *********************************************************
194 $ hg churn -T 'alltogether'
194 $ hg churn -T 'alltogether'
195 alltogether 11 *********************************************************
195 alltogether 11 *********************************************************
196
196
197 $ cd ..
197 $ cd ..
198
199 count lines that look like headings but are not
200
201 $ hg init not-headers
202 $ cd not-headers
203 $ cat > a <<EOF
204 > diff
205 > @@ -195,3 +195,21 @@
206 > -- a/tests/test-churn.t
207 > ++ b/tests/test-churn.t
208 > EOF
209 $ hg ci -Am adda -u user1
210 adding a
211 $ hg churn --diffstat
212 user1 +4/-0 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
213 $ hg rm a
214 $ hg ci -Am removea -u user1
215 $ hg churn --diffstat
216 user1 +4/-4 +++++++++++++++++++++++++++---------------------------
General Comments 0
You need to be logged in to leave comments. Login now