Changelog Generator
Paste git log output, get a grouped CHANGELOG.md section — Conventional Commits sorted into Features, Fixes and Breaking Changes.
Paste git log output on the left to build a CHANGELOG.md section.
Press / to jump to the paste pane, or load the sample.
Press ? for shortcuts · Section choices are remembered on this device — the pasted log is not.
Do it offline:$ git log --pretty=format:%s v1.0.0..HEAD
How to use it
- Run git log --pretty=format:%s v1.0.0..HEAD in your repository — or git log --oneline — and copy the output for the release range.
- Paste it into the left pane. The paste shape is detected automatically and every commit is read as a Conventional Commit.
- Set the version for the ## heading, pick the section order, and untick any of the four release sections you don't want.
- Check the skipped-lines strip, then copy the Markdown or download it as CHANGELOG.md and drop the section into your changelog.
Paste the output of git log and get back a CHANGELOG.md section with commits grouped under Features, Bug Fixes, Performance and Reverts, and breaking changes pulled into their own block. Three paste shapes are auto-detected — --oneline, bare subjects from --pretty=format:%s, and the default block format. Lines that aren't Conventional Commits are skipped and counted, never guessed, and the whole run happens on this device.
Examples
4f2a9c1 feat(parser): accept oneline pastes
8b3d2e0 fix(detect): refuse mixed pastes
1c9f4a7 docs: describe the paste shapes
a52e881 tweak wording in the README## [1.1.0] - 2026-08-18
### Features
* **parser:** accept oneline pastes
### Bug Fixes
* **detect:** refuse mixed pastes
A git log --oneline paste. The docs line is a valid Conventional Commit, but docs isn't one of the four release sections, so it is filtered by the section choices and reported as such. The last line carries no type at all — it lands in the skipped count instead of being guessed into a section.
feat(api)!: version keys are required
fix: keep totals stable## [2.0.0] - 2026-08-18
### Features
* **api:** version keys are required
### Bug Fixes
* keep totals stable
### BREAKING CHANGES
* **api:** version keys are required
Bare subjects from --pretty=format:%s. The bang in feat(api)! marks a breaking change, so that commit appears twice — once under Features as an ordinary entry, once under BREAKING CHANGES at the end. With no BREAKING CHANGE footer to quote, the subject line itself is the notice.
Every example on this page is executed against the same engine that powers the tool, on every build.
Gotchas worth knowing
Skipped, filtered and counted — never guessed
A line that doesn't parse as type(scope): subject — a merge commit, a fixup line, a plain sentence — is skipped by shape and added to the skipped count; nothing infers a section for it. A commit that parses but has no section under your choices — a type without a release section (docs, chore, test and the rest) or one you've unticked — is filtered and counted separately, unless it is breaking, in which case it surfaces under BREAKING CHANGES and counts as grouped. Both counts are computed from the paste in front of you and render together when both apply, so the strip above the output always accounts for every line.
The headings are conventional-changelog's, not Keep a Changelog's
Section names and order follow the convention popularised by the conventional-changelog tooling: Features, Bug Fixes, Performance, Reverts, then BREAKING CHANGES at the end. Keep a Changelog is a different convention with a different vocabulary — Added, Changed, Deprecated, Removed — and this tool doesn't write it. The output follows the cited heading convention; it doesn't claim byte-parity with any generator's rendering.
Tag ranges and compare links stay in your hands
The tool reads exactly the log text you paste — it can't see your repository's tags, so scoping the release is the v1.0.0..HEAD range on your git log command. Version-compare links, the linked [1.1.0] heading pointing at a compare URL, aren't generated in this version; the heading is plain text you can link up in your editor if your host needs it.
Common errors
This paste mixes shapes — some lines start with a commit hash and some don't. Paste one shape: git log --oneline, bare subjects from git log --pretty=format:%s, or the full git log block format.- Auto-detection reads the whole paste as one of the three accepted shapes. A mixed paste usually means two commands' outputs were combined, or a subject column was hand-edited — re-copy the output of a single git log command and the shape resolves.
No line parses as a Conventional Commit header (type: subject) — there is nothing to group.- Grouping is driven entirely by the type in each header. A history written without Conventional Commits can't be sorted into sections honestly, so the tool refuses instead of inventing types. The skipped strip shows the same accounting when only some lines fail.
More than 5,000 commits in one paste — narrow the range first: git log --pretty=format:%s v1.0.0..HEAD- A changelog section describes one release, and 5,000 commits is past any release's worth of lines. A tag range keeps the paste to the commits the section is actually about.
Pastes over 1 MiB aren't converted — trim to the release range first: git log --pretty=format:%s v1.0.0..HEAD- The island refuses oversized pastes before parsing starts, and the banner carries the log command that produces a right-sized one. The cap is a byte measure of the paste, not a commit count — block-format pastes hit it soonest because they carry authors, dates and bodies.
FAQ
Which git log command should I paste?
Any of three shapes works: git log --oneline for hash-and-subject lines, git log --pretty=format:%s for bare subjects — the cleanest input — or the default git log block output. Scope it to the release with a range such as v1.0.0..HEAD. The block format is the only shape that carries commit bodies, so BREAKING CHANGE footers are read from it; the other two rely on the ! marker in the header line.
Why were some of my lines skipped?
Grouping needs the Conventional Commits header shape — a type, an optional scope in parentheses, a colon and a subject, as in fix(parser): handle empty scopes. Merge commits, fixup lines and free-form subjects don't carry a type, so the tool skips them and reports the count in the strip above the output rather than guessing a section for them.
How do breaking changes get their own section?
A commit marks itself breaking with ! after the type or scope — feat(api)!: — or with a BREAKING CHANGE: footer in its body. Either marker adds an entry to the BREAKING CHANGES section at the end of the output; when a footer exists its text is quoted, otherwise the subject line is. The commit also keeps its place under its own type, matching the convention's rendering.
Keyboard shortcuts
- /
- Focus the git log pane
- ⌘/Ctrl + S
- Download CHANGELOG.md
- ⌘/Ctrl + C
- Copy output (with nothing selected)
- ⌘/Ctrl + Shift + C
- Copy output
- t
- Switch theme
- ? or ⌘/Ctrl + /
- Open the shortcut reference
- Esc
- Close dialogs