GitStats is set of fully configurable language breakdown Cards for your Github Profile.
I didn´t like the functionality, nor the flexibility of existing projects. Hope you enjoy :)
-
README-driven config |
gitstats:configblocks allow easy configurability. -
Managed display | Paired
gitstats:displaymarkers auto generate Cards. -
Flexible timeframe | Use
all-timelanguage bytes or recent weeks. -
Two styles |
normalextended bar & list.compactlabeled bar. -
Language cleanup | Hide languages, group entries into
Other, and fully configure visibility.
Add this workflow to the repository where the Cards should be displayed.
For a GitHub profile README, that is usually YOUR_USERNAME/YOUR_USERNAME.
GitStats is published as a reusable GitHub Action.
the workflow decides when the action runs and grants write permission to the current repository.
GitStats reads README config blocks, generates Cards & updates managed display sections automatically.
name: GitStats
on:
workflow_dispatch:
schedule:
- cron: "17 3 * * 1"
push:
branches:
- main
paths-ignore:
- "profile/*.svg"
concurrency:
group: gitstats-${{ github.ref }}
cancel-in-progress: true
jobs:
languages:
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: write
steps:
- uses: actions/checkout@v6
- name: Generate language stats
uses: One-Simon/GitStats@main
with:
token: ${{ secrets.GITSTATS_TOKEN }}
username: YOUR_USERNAMEAdd a Config Block inside the README for each Card.
Each Card can have a set of settings that let you customize them extensively.
Almost all of them are optional. Only set the values you want to change.
This is the minimal necessary setup:
<!-- gitstats:config
style: normal
timeframe: all-time
gitstats:config -->
<!-- gitstats:config
style: compact
timeframe: 8
gitstats:config -->GitStats displays the Cards between the markers with generated image tags.
You do not need to add SVG paths or <img> tags yourself.
The surrounding <div> is yours, you can center the cards, place them in a table, or use any other README layout GitHub supports.
<div align="center">
<!-- gitstats:display -->
<!-- gitstats:display -->
</div>Tip
You can also display the Cards seperate from one another and show them wherever you like.
For this, name the Configuration blocks however you like:
<!-- gitstats:config allTime
style: normal
timeframe: all-time
gitstats:config -->
<!-- gitstats:config recent
style: compact
timeframe: 8
gitstats:config -->The block names become the Card names.
These examples generate profile/allTime.svg and profile/recent.svg.
Then display them seperately:
<div align="center">
<!-- gitstats:display allTime-->
<!-- gitstats:display allTime-->
</div>
-----------------
<div align="center">
<!-- gitstats:display recent-->
<!-- gitstats:display recent-->
</div>GitStats needs a Personal Access Token because the default GITHUB_TOKEN only has access to the repository running the workflow.
Recommended secret name:
GITSTATS_TOKEN
For classic Personal Access Tokens:
repo
read:user
For fine-grained Personal Access Tokens:
- Set Repository access to the repositories you want included, or All repositories.
- Set Repository permissions -> Metadata to Read-only.
- For recent renders such as
timeframe: 8, also set Repository permissions -> Contents to Read-only. - If the token is scoped to an organization with SSO, authorize the token for that organization.
Important
All-time cards use GitHub language byte metadata. Recent cards also ask GitHub for commit file paths and change counts, which is why fine-grained tokens need Contents: read. GitStats does not write repository contents or include private repository/source names in the generated SVG.
Run the Workflow / Action once from the Actions tab.
After the first successful run, the generated Cards will be committed and displayed in your README.
The workflow example above also refreshes the Cards automatically once per week.
Tip
To change a card immediately, edit the matching gitstats:config block and rerun the workflow.
Warning
DO NOT eidt the generated content between display markers.
These are the settings you will most likely change first.
| Setting | Default | Description |
|---|---|---|
title |
Automatic | Optional card title override. Defaults to Most Used Languages for all-time, or Recent Languages for numbered timeframes. |
timeframe |
all-time |
all-time uses GitHub language bytes. A positive integer, such as 8, uses recent commit changes from that many weeks. |
style |
normal |
normal renders the full card with a list. compact renders a thicker labeled bar. |
These settings change how each generated card is rendered or displayed in your README.
| Setting | Default | Description |
|---|---|---|
show-values |
true |
Shows byte or change totals in the normal renderer. Compact cards always show percentages only. |
display-width |
100% |
Width attribute for this card's generated <img> tag inside the managed display section. |
display-alt |
Automatic | Alt text for this card's generated <img> tag inside the managed display section. |
These settings control which languages appear and how smaller entries are handled.
| Setting | Default | Description |
|---|---|---|
hide-languages |
HTML,CSS,JSON |
Comma-separated languages to exclude after loading all detected languages. |
grouping |
true |
Groups the smallest languages into Other until the bucket is near 5%. |
max-languages |
10 |
Positive integer maximum for displayed entries, including Other. Overflow languages are grouped into Other. |
These settings control which repositories GitStats reads from GitHub.
| Setting | Default | Description |
|---|---|---|
include-forks |
false |
Includes forked repositories. |
include-archived |
false |
Includes archived repositories. |
include-profile-repo |
false |
Includes the username/username profile repository. |
affiliation |
owner |
Repository affiliation passed to GitHub. Use owner,collaborator,organization_member for broader access. |
visibility |
all |
Repository visibility passed to GitHub. |
You are able to choose to group small language sets and dynamically decide how much.
When grouping: true - GitStats groups the smallest languages into Other until that bucket is close to 5%, preferring a smaller bucket over larger ones.
Using max-languages you can set how many languages should be displayed (bar & list) - all remaining get grouped into Other.
If grouping is enabled, but the amount is larger than max-languages - the lowest remaining entries are also merged into Other.
Mix style, timeframe, and the other settings however you want. These four examples are the same configurable viewer with different settings.
<!-- gitstats:config all-time-normal
style: normal
timeframe: all-time
gitstats:config --><!-- gitstats:config all-time-compact
style: compact
timeframe: all-time
gitstats:config --><!-- gitstats:config recent-normal
style: normal
timeframe: 8
gitstats:config --><!-- gitstats:config recent-compact
style: compact
timeframe: 8
gitstats:config -->README config blocks drive Card generation.
Workflow inputs provide global defaults and automation behavior.
| Input | Default | Description |
|---|---|---|
token |
Required | GitHub token used to read repositories, language data, and recent commit data. |
username |
Repository owner | GitHub username to generate stats for. |
readme-config |
README.md |
README path containing GitStats config blocks. |
commit |
true |
Commit and push changed generated SVGs and README display updates using the workflow checkout credentials. |
max-languages |
10 |
Positive integer maximum for displayed entries, including Other. |
grouping |
true |
Group the smallest languages into Other until the bucket is near 5%. |
hide-languages |
HTML,CSS,JSON |
Languages to exclude after loading all detected languages. |
include-forks |
false |
Include forked repositories. |
include-archived |
false |
Include archived repositories. |
include-profile-repo |
false |
Include the username/username profile repository. |
affiliation |
owner |
Repository affiliation passed to GitHub. |
visibility |
all |
Repository visibility passed to GitHub. |
title |
Automatic | Global card title fallback. README config blocks can override it per card. |
timeframe |
all-time |
all-time for language bytes, or a positive integer number of weeks for recent changes. |
style |
normal |
Rendering style. |
show-values |
true |
Show byte or change totals in the normal renderer. |
user-agent |
GitStats-language-card |
User-Agent used for GitHub API requests. |
api-request-timeout-ms |
15000 |
Maximum time to wait for each GitHub API request before failing or retrying. |
api-max-retry-seconds |
60 |
Maximum total time to spend retrying safe transient GitHub API failures. |
api-rate-limit-buffer |
50 |
Minimum GitHub API requests to leave unused when estimating recent card commit-detail work. |
GitStats reads every gitstats:config block in your README and generates one Card for each block.
<!-- gitstats:config example-name
style: normal
timeframe: all-time
gitstats:config -->Save Paths get auto generated based on naming & Card type. Named blocks get saved on their name path. Named block names may contain only letters, numbers, dots, underscores, and hyphens, and cannot start with a dot.
| Config type | Output path |
|---|---|
Named block, such as most-used |
profile/most-used.svg |
| Unnamed all-time normal block | profile/GitStats-MostUsed-normal.svg |
| Duplicate generated path | GitStats appends -2, -3, and so on. |
Named display markers display the card of the corresponding block.
For example, <!-- gitstats:display most-used --> displays the card generated by <!-- gitstats:config most-used.
| Marker | Behavior |
|---|---|
<!-- gitstats:display --> |
Displays all generated cards in config order. |
<!-- gitstats:display most-used --> |
Displays only the matching named config block. |
Note
Display markers should be paired, not used alone. GitStats rewrites only the content between the markers.
Warning
Only image tags & image width get injected. To adjust the width, use the display-width: setting
Layout HTML has to be OUTSIDE the markers - use the injected Cards however you like.
<div align="center">
<!-- gitstats:display -->
<!-- gitstats:display -->
</div>- Reads repository metadata visible to the token.
- Filters repositories by owner, forks, archived status, and profile repository settings.
- For a numbered
timeframe, reads recent commit file paths and change counts. - For
timeframe: all-time- reads GitHub language byte totals. - Applies
hide-languages, dynamic grouping, andmax-languages. - Renders every SVG in memory before writing any file.
- Rewrites the marked README display section with matching image tags and spacing only after all cards succeed.
- Auto commits changed generated SVGs and README display updates with
[skip ci], and refuses to push if the remote branch moved while the workflow was running.
Important
GitHub may cache README images for a short while after the workflow updates the SVG files. If the raw SVG file is correct but the README still shows the old card, wait a bit and refresh later.
GitHub caches images rendered inside READMEs. Check the SVG file directly in the repository, for example profile/most-used.svg. If that raw file is updated, the workflow worked and the README image cache should catch up after a little while.
The stats token could be missing, blank, expired, revoked, or copied with the wrong value. GitStats trims the token and checks authentication before generating cards, so this error should happen before any SVG or README file is written. Rotate the secret, confirm the workflow uses the same secret name, and rerun the workflow.
Fine-grained tokens need Metadata: read for all-time cards and Contents: read for recent cards. If organization repositories are included, make sure SSO is authorized for the token. GitStats includes the endpoint type, card name, repository, request id, accepted permissions, and rate-limit state in the failure message when GitHub provides those headers.
GitStats reads repository, language, and commit data through the GitHub API. Wait until the rate limit reset time shown in the error, then rerun the workflow from the Actions tab. Recent cards can use more requests than all-time cards because they inspect commits and changed files inside the selected timeframe.
GitStats caches repeated work across matching cards and estimates the commit-detail budget before writing files. If the remaining quota is too low, it fails early instead of publishing partial stats. Lower the recent timeframe, exclude noisy repositories, or rerun after reset.
GitStats fetches the checked-out branch before committing. If another push lands while the workflow is generating cards, GitStats fails clearly instead of pushing stale generated README content. Rerun the workflow after the branch is up to date.
Make sure the workflow uses readme-config: README.md or leaves that input at its default. Config blocks inside fenced code examples are ignored, so active blocks should live directly in the README body.
Add paired <!-- gitstats:display --> markers to your README. GitStats needs those markers to know where it may write the generated image HTML. If you use a named display block, make sure the name matches a named gitstats:config block.
- All-time numbers are GitHub language byte counts, not lines of code.
- Recent numbers are commit file change counts, usually additions plus deletions. They show activity, not how much code exists in that language.
- SVGs are vector graphics. Use
display-widthto control the generated image width, and use layout HTML outside the display markers for positioning. - Recent language detection is based on changed file paths and extensions.
- Private repository names and source code are not written to the SVG.
- Generated SVGs are public if committed to a public repository.
- Automatic commits use the workflow
GITHUB_TOKENfromactions/checkout, not the stats token.
MIT