Skip to content

Commit 465931a

Browse files
authored
fix: let commit_begin back to work and add docs (#129)
1 parent a03381e commit 465931a

File tree

4 files changed

+92
-10
lines changed

4 files changed

+92
-10
lines changed

docs/source/configuration.rst

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
2+
Configuration
3+
=============
4+
5+
You can create a ``gitstats.conf`` file in the current directory to customize the configuration.
6+
7+
* ``max_domains`` - Maximum number of domains to display in "Domains by Commits". Default: ``10``.
8+
* ``max_ext_length`` - Maximum length of file extensions shown in statistics. Default: ``10``.
9+
* ``style`` - CSS stylesheet for the generated report. Default: ``gitstats.css``.
10+
* ``max_authors`` - Maximum number of authors to list in "Authors". Default: ``20``.
11+
* ``authors_top`` - Number of top authors to highlight. Default: ``5``.
12+
* ``commit_begin`` - Start of commit range (empty = include all commits). For example, ``10`` for last 10 commits. Default: ``""`` (empty).
13+
* ``commit_end`` - End of commit range. Default: ``HEAD``.
14+
* ``linear_linestats`` - Enable linear history for line statistics (``1`` = enabled, ``0`` = disabled). Default: ``1``.
15+
* ``project_name`` - Project name to display (default: repository directory name). Default: ``""`` (empty).
16+
* ``processes`` - Number of parallel processes to use when gathering data. Default: ``8``.
17+
* ``start_date`` - Starting date for commits, passed as --since to Git (optional). Format: ``YYYY-MM-DD``. Default: ``""`` (empty).
18+
19+
Here is an example ``gitstats.conf`` file:
20+
21+
.. code-block:: ini
22+
23+
[gitstats]
24+
max_domains = 10
25+
max_ext_length = 10
26+
style = gitstats.css
27+
max_authors = 20
28+
authors_top = 5
29+
commit_begin = 10
30+
commit_end = HEAD
31+
linear_linestats = 1
32+
project_name =
33+
processes = 8
34+
start_date =
35+
36+
You can also override configuration values using the ``-c key=value`` option when running the ``gitstats`` command.
37+
38+
For example:
39+
40+
.. code-block:: bash
41+
42+
gitstats . report -c max_authors=10 -c authors_top=3
43+
44+
This command will generate a report with a maximum of 10 authors displayed and the top 3 authors shown.

docs/source/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Welcome to GitStats documentation!
1111

1212
installation
1313
usage
14+
configuration
1415
integration
1516
faq
1617

gitstats/main.py

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -139,17 +139,30 @@ def collect(self, dir):
139139
DataCollector.collect(self, dir)
140140

141141
self.total_authors += int(
142-
get_pipe_output(["git shortlog -s %s" % get_log_range(), "wc -l"])
142+
get_pipe_output(
143+
["git shortlog -s %s" % get_log_range("HEAD", False), "wc -l"]
144+
)
143145
)
144146
# self.total_lines = int(getoutput('git-ls-files -z |xargs -0 cat |wc -l'))
145147

146148
# tags
149+
# Only include tags that are reachable within the commit range
150+
commit_range = get_commit_range("HEAD", False)
151+
tag_commits = (
152+
get_pipe_output([f"git rev-list {commit_range}"]).strip().split("\n")
153+
)
154+
tag_commits_set = set(tag_commits) if tag_commits[0] else set()
155+
147156
lines = get_pipe_output(["git show-ref --tags"]).split("\n")
148157
for line in lines:
149158
if len(line) == 0:
150159
continue
151160
(hash, tag) = line.split(" ")
152161

162+
# Only include tags whose commit is in our range
163+
if hash not in tag_commits_set:
164+
continue
165+
153166
tag = tag.replace("refs/tags/", "")
154167
output = get_pipe_output(
155168
['git log "%s" --pretty=format:"%%at %%aN" -n 1' % hash]
@@ -170,6 +183,8 @@ def collect(self, dir):
170183
}
171184

172185
# collect info on tags, starting from latest
186+
# Only collect statistics for commits within our range
187+
commit_range = get_commit_range("HEAD", False)
173188
tags_sorted_by_date_desc = [
174189
el[1]
175190
for el in reversed(
@@ -178,15 +193,22 @@ def collect(self, dir):
178193
]
179194
prev = None
180195
for tag in reversed(tags_sorted_by_date_desc):
181-
cmd = 'git shortlog -s "%s"' % tag
196+
# Modify command to only include commits within our range
197+
cmd = f'git shortlog -s "{tag}"'
182198
if prev is not None:
183-
cmd += ' "^%s"' % prev
199+
cmd += f' "^{prev}"'
200+
# Intersect with our commit range
201+
cmd += f" {commit_range}"
184202
output = get_pipe_output([cmd])
185203
if len(output) == 0:
186204
continue
187205
prev = tag
188206
for line in output.split("\n"):
207+
if len(line.strip()) == 0:
208+
continue
189209
parts = re.split(r"\s+", line, 2)
210+
if len(parts) < 3:
211+
continue
190212
commits = int(parts[1])
191213
author = parts[2]
192214
self.tags[tag]["commits"] += commits
@@ -197,7 +219,7 @@ def collect(self, dir):
197219
lines = get_pipe_output(
198220
[
199221
'git rev-list --pretty=format:"%%at %%ai %%aN <%%aE>" %s'
200-
% get_log_range("HEAD"),
222+
% get_log_range("HEAD", False),
201223
"grep -v ^commit",
202224
]
203225
).split("\n")
@@ -335,7 +357,7 @@ def collect(self, dir):
335357
get_pipe_output(
336358
[
337359
'git rev-list --pretty=format:"%%at %%T" %s'
338-
% get_log_range("HEAD"),
360+
% get_log_range("HEAD", False),
339361
"grep -v ^commit",
340362
]
341363
)
@@ -448,7 +470,7 @@ def collect(self, dir):
448470
lines = get_pipe_output(
449471
[
450472
'git log --shortstat %s --pretty=format:"%%at %%aN" %s'
451-
% (extra, get_log_range("HEAD"))
473+
% (extra, get_log_range("HEAD", False))
452474
]
453475
).split("\n")
454476
lines.reverse()
@@ -523,7 +545,7 @@ def collect(self, dir):
523545
lines = get_pipe_output(
524546
[
525547
'git log --shortstat --date-order --pretty=format:"%%at %%aN" %s'
526-
% (get_log_range("HEAD"))
548+
% (get_log_range("HEAD", False))
527549
]
528550
).split("\n")
529551
lines.reverse()
@@ -804,7 +826,11 @@ def main() -> int:
804826
key, value = item.split("=", 1)
805827
if key not in conf:
806828
parser.error(f'No such key "{key}" in config')
807-
conf[key] = value
829+
# Convert numeric strings to integers to match config file behavior
830+
if value.isdigit():
831+
conf[key] = int(value)
832+
else:
833+
conf[key] = value
808834
except ValueError:
809835
parser.error("Config must be in the form key=value")
810836

gitstats/utils.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,20 @@ def get_pipe_output(cmds, quiet=False):
100100

101101
def get_commit_range(defaultrange="HEAD", end_only=False):
102102
if len(conf["commit_end"]) > 0:
103-
if end_only or len(conf["commit_begin"]) == 0:
103+
commit_begin = conf["commit_begin"]
104+
105+
# Convert commit_begin to string for consistent handling
106+
commit_begin_str = str(commit_begin)
107+
108+
# If end_only or no commit_begin specified, return just the end
109+
if end_only or len(commit_begin_str) == 0:
104110
return conf["commit_end"]
105-
return "%s..%s" % (conf["commit_begin"], conf["commit_end"])
111+
112+
# Handle numeric commit_begin as "N commits ago"
113+
if commit_begin_str.isdigit():
114+
commit_begin_str = f"{conf['commit_end']}~{commit_begin_str}"
115+
116+
return "%s..%s" % (commit_begin_str, conf["commit_end"])
106117
return defaultrange
107118

108119

0 commit comments

Comments
 (0)