Skip to main content

Template Examples

This page showcases complete template examples demonstrating different changelog formats. Each example includes the TOML configuration and resulting output.

Keep a Changelog

A template following the Keep a Changelog format.

Configuration

# examples/keepachangelog.toml

[changelog]
header = """
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
"""

body = """
{% if version -%}
    ## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
{% else -%}
    ## [Unreleased]
{% endif -%}
{% for group, commits in commits | group_by(attribute="group") %}
    ### {{ group | upper_first }}
    {% for commit in commits %}
        - {{ commit.message | split(pat="\n") | first | upper_first | trim }}
    {% endfor %}
{% endfor %}
"""

footer = """
{% for release in releases -%}
    {% if release.version -%}
        {% if release.previous.version -%}
            [{{ release.version | trim_start_matches(pat="v") }}]: \
                https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}\
                    /compare/{{ release.previous.version }}..{{ release.version }}
        {% endif -%}
    {% else -%}
        [unreleased]: https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}\
            /compare/{{ release.previous.version }}..HEAD
    {% endif -%}
{% endfor %}
<!-- generated by git-cliff -->
"""

trim = true

[git]
conventional_commits = true
filter_unconventional = false

commit_parsers = [
    { message = "^[a|A]dd", group = "Added" },
    { message = "^[s|S]upport", group = "Added" },
    { message = "^[r|R]emove", group = "Removed" },
    { message = "^.*: add", group = "Added" },
    { message = "^.*: support", group = "Added" },
    { message = "^.*: remove", group = "Removed" },
    { message = "^.*: delete", group = "Removed" },
    { message = "^test", group = "Fixed" },
    { message = "^fix", group = "Fixed" },
    { message = "^.*: fix", group = "Fixed" },
    { message = "^.*", group = "Changed" },
]

sort_commits = "oldest"

Output

# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added

- Support multiple file formats

### Changed

- Use cache while fetching pages

## [1.0.1] - 2021-07-18

### Added

- Add release script

### Changed

- Expose string functions

## [1.0.0] - 2021-07-18

### Added

- Add tested usage example
- Add ability to parse arrays
- Add README.md

### Changed

- Initial commit

### Fixed

- Rename help argument due to conflict

[unreleased]: https://github.com/orhun/git-cliff-readme-example/compare/v1.0.1..HEAD
[1.0.1]: https://github.com/orhun/git-cliff-readme-example/compare/v1.0.0..v1.0.1

<!-- generated by git-cliff -->

Detailed Format

A detailed changelog showing commit IDs and footers.

Configuration

# examples/detailed.toml

[changelog]
header = """
# Changelog

All notable changes to this project will be documented in this file.
"""

body = """
{% if version %}\
    ## {{ version | trim_start_matches(pat="v") }} - {{ timestamp | date(format="%Y-%m-%d") }}
{% else %}\
    ## Unreleased
{% endif %}\
{% if previous %}\
    {% if previous.commit_id and commit_id %}
        [{{ previous.commit_id | truncate(length=7, end="") }}]({{ previous.commit_id }})...\
            [{{ commit_id | truncate(length=7, end="") }}]({{ commit_id }})
    {% endif %}\
{% endif %}\
{% for group, commits in commits | group_by(attribute="group") %}
    ### {{ group | upper_first }}
    {% for commit in commits %}
        - {{ commit.message | split(pat="\n") | first | upper_first | trim }} ([{{ commit.id | truncate(length=7, end="") }}]({{ commit.id }}))\
          {% if commit.footers %}\
            {% for footer in commit.footers -%}
                , {{ footer.token }}{{ footer.separator }}{{ footer.value }}\
            {% endfor %}\
          {% endif %}
    {% endfor %}
{% endfor %}
"""

footer = """
<!-- generated by git-cliff -->
"""

trim = true

[git]
conventional_commits = true
filter_unconventional = false

commit_parsers = [
    { message = "^feat", group = "Features" },
    { message = "^fix", group = "Bug Fixes" },
    { message = "^doc", group = "Documentation" },
    { message = "^perf", group = "Performance" },
    { message = "^refactor", group = "Refactor" },
    { message = "^style", group = "Styling" },
    { message = "^test", group = "Testing" },
    { message = "^chore\\(release\\): prepare for", skip = true },
    { message = "^chore|^ci", group = "Miscellaneous Tasks" },
]

sort_commits = "oldest"

Output

# Changelog

All notable changes to this project will be documented in this file.

## Unreleased

### Features

- Support multiple file formats (a9d4050)
- Use cache while fetching pages (df6aef4)

## [1.0.1] - 2021-07-18

ad27b43...06412ac

### Miscellaneous Tasks

- Add release script (06412ac)

### Refactor

- Expose string functions (e4fd3cf)

## [1.0.0] - 2021-07-18

### Bug Fixes

- Rename help argument due to conflict (9add0d4)

### Documentation

- Add README.md (81fbc63)
- Add tested usage example (ad27b43)

### Features

- Add ability to parse arrays (a140cef)

<!-- generated by git-cliff -->

Scoped Commits

Group commits by scope within each type.

Configuration

# examples/scoped.toml

[changelog]
header = """
# Changelog

All notable changes to this project will be documented in this file.
"""

body = """
{% if version %}\
    ## {{ version | trim_start_matches(pat="v") }} - {{ timestamp | date(format="%Y-%m-%d") }}
{% else %}\
    ## Unreleased
{% endif %}\
{% for group, commits in commits | group_by(attribute="group") %}
    ### {{ group | upper_first }}
    {% for group, commits in commits | group_by(attribute="scope") %}
        #### {{ group | upper_first }}
        {% for commit in commits %}
            - {{ commit.message | upper_first }}
        {% endfor %}
    {% endfor %}\
{% endfor %}
"""

footer = """
<!-- generated by git-cliff -->
"""

trim = true

[git]
conventional_commits = true
filter_unconventional = true

commit_parsers = [
    { message = "^feat", group = "Features" },
    { message = "^fix", group = "Bug Fixes" },
    { message = "^doc", group = "Documentation", default_scope = "unscoped" },
    { message = "^perf", group = "Performance" },
    { message = "^refactor", group = "Refactor" },
    { message = "^style", group = "Styling" },
    { message = "^test", group = "Testing" },
    { message = "^chore\\(release\\): prepare for", skip = true },
    { message = "^chore", group = "Miscellaneous Tasks" },
]

sort_commits = "oldest"

Output

# Changelog

All notable changes to this project will be documented in this file.

## Unreleased

### Features

#### Cache

- Use cache while fetching pages

#### Config

- Support multiple file formats

## 1.0.1 - 2021-07-18

### Miscellaneous Tasks

#### Release

- Add release script

### Refactor

#### Parser

- Expose string functions

## 1.0.0 - 2021-07-18

### Bug Fixes

#### Args

- Rename help argument due to conflict

### Documentation

#### Example

- Add tested usage example

#### Project

- Add README.md

### Features

#### Parser

- Add ability to parse arrays

<!-- generated by git-cliff -->

Styled with Emojis and Scopes

The default git-cliff template with emoji icons and inline scopes.

Configuration

# cliff.toml (git-cliff default)

[remote.github]
owner = "orhun"
repo = "git-cliff"

[changelog]
header = """
# Changelog

All notable changes to this project will be documented in this file.
"""

body = """
{%- macro remote_url() -%}
  https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}
{%- endmacro -%}

{% macro print_commit(commit) -%}
    - {% if commit.scope %}*({{ commit.scope }})* {% endif %}\
        {% if commit.breaking %}[**breaking**] {% endif %}\
        {{ commit.message | upper_first }} - \
        ([{{ commit.id | truncate(length=7, end="") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))
{% endmacro -%}

{% if version %}\
    {% if previous.version %}\
        ## [{{ version | trim_start_matches(pat="v") }}]\
          ({{ self::remote_url() }}/compare/{{ previous.version }}..{{ version }}) - {{ timestamp | date(format="%Y-%m-%d") }}
    {% else %}\
        ## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
    {% endif %}\
{% else %}\
    ## [unreleased]
{% endif %}\

{% for group, commits in commits | group_by(attribute="group") %}
    ### {{ group | striptags | trim | upper_first }}
    {% for commit in commits
    | filter(attribute="scope")
    | sort(attribute="scope") %}
        {{ self::print_commit(commit=commit) }}
    {%- endfor %}
    {% for commit in commits %}
        {%- if not commit.scope -%}
            {{ self::print_commit(commit=commit) }}
        {% endif -%}
    {% endfor -%}
{% endfor -%}

{%- if github -%}
{% if github.contributors | filter(attribute="is_first_time", value=true) | length != 0 %}
  ## New Contributors ❤️
{% endif %}\
{% for contributor in github.contributors | filter(attribute="is_first_time", value=true) %}
  * @{{ contributor.username }} made their first contribution
    {%- if contributor.pr_number %} in \
      [#{{ contributor.pr_number }}]({{ self::remote_url() }}/pull/{{ contributor.pr_number }}) \
    {%- endif %}
{%- endfor -%}
{%- endif %}
"""

footer = """
<!-- generated by git-cliff -->
"""

trim = true

[git]
conventional_commits = true
filter_unconventional = true

commit_parsers = [
  { message = "^feat", group = "<!-- 0 -->⛰️  Features" },
  { message = "^fix", group = "<!-- 1 -->🐛 Bug Fixes" },
  { message = "^doc", group = "<!-- 3 -->📚 Documentation" },
  { message = "^perf", group = "<!-- 4 -->⚡ Performance" },
  { message = "^refactor", group = "<!-- 2 -->🚜 Refactor" },
  { message = "^style", group = "<!-- 5 -->🎨 Styling" },
  { message = "^test", group = "<!-- 6 -->🧪 Testing" },
  { message = "^chore\\(release\\): prepare for", skip = true },
  { message = "^chore|^ci", group = "<!-- 7 -->⚙️ Miscellaneous Tasks" },
]

sort_commits = "newest"

Output

# Changelog

All notable changes to this project will be documented in this file.

## [unreleased]

### ⛰️  Features

- *(cache)* Use cache while fetching pages - ([df6aef4](https://github.com/orhun/git-cliff/commit/df6aef4))
- *(config)* Support multiple file formats - ([a9d4050](https://github.com/orhun/git-cliff/commit/a9d4050))

## [1.0.1] - 2021-07-18

### 🚜 Refactor

- *(parser)* Expose string functions - ([e4fd3cf](https://github.com/orhun/git-cliff/commit/e4fd3cf))

### ⚙️ Miscellaneous Tasks

- *(release)* Add release script - ([06412ac](https://github.com/orhun/git-cliff/commit/06412ac))

## [1.0.0] - 2021-07-18

### ⛰️  Features

- *(parser)* Add ability to parse arrays - ([a140cef](https://github.com/orhun/git-cliff/commit/a140cef))

### 🐛 Bug Fixes

- *(args)* Rename help argument due to conflict - ([9add0d4](https://github.com/orhun/git-cliff/commit/9add0d4))

### 📚 Documentation

- *(example)* [**breaking**] Add tested usage example - ([ad27b43](https://github.com/orhun/git-cliff/commit/ad27b43))
- *(project)* Add README.md - ([81fbc63](https://github.com/orhun/git-cliff/commit/81fbc63))

<!-- generated by git-cliff -->

Release Statistics

Include commit statistics in each release.

Configuration

# examples/statistics.toml

[changelog]
header = """
# Changelog

All notable changes to this project will be documented in this file.
"""

body = """
{% if version %}\
    ## {{ version | trim_start_matches(pat="v") }} - {{ timestamp | date(format="%Y-%m-%d") }}
{% else %}\
    ## Unreleased
{% endif %}\
{% for group, commits in commits | group_by(attribute="group") %}
    ### {{ group | upper_first }}
    {% for commit in commits %}
        - {{ commit.message | split(pat="\n") | first | upper_first | trim }}
    {% endfor %}
{% endfor %}

### Commit Statistics

- {{ statistics.commit_count }} commit(s) contributed to the release.
- {{ statistics.commits_timespan | default(value=0) }} day(s) passed between the first and last commit.
- {{ statistics.conventional_commit_count }} commit(s) parsed as conventional.
- {{ statistics.links | length }} linked issue(s) detected in commits.
{%- if statistics.links | length > 0 %}
  {%- for link in statistics.links %}
    - [{{ link.text }}]({{ link.href }}) (referenced {{ link.count }} time(s))
  {%- endfor %}
{%- endif %}
{%- if statistics.days_passed_since_last_release %}
- {{ statistics.days_passed_since_last_release }} day(s) passed between releases.
{%- endif %}
"""

footer = """
<!-- generated by git-cliff -->
"""

trim = true

[git]
conventional_commits = true
filter_unconventional = false

commit_parsers = [
    { message = "^feat", group = "Features" },
    { message = "^fix", group = "Bug Fixes" },
    { message = "^doc", group = "Documentation" },
    { message = "^perf", group = "Performance" },
    { message = "^refactor", group = "Refactor" },
    { message = "^style", group = "Styling" },
    { message = "^test", group = "Testing" },
    { message = "^chore", group = "Miscellaneous Tasks" },
    { body = ".*security", group = "Security" },
]

sort_commits = "oldest"

Output

# Changelog

All notable changes to this project will be documented in this file.

## Unreleased

### Features

- Support multiple file formats
- Use cache while fetching pages

### Commit Statistics

- 2 commit(s) contributed to the release.
- 0 day(s) passed between the first and last commit.
- 2 commit(s) parsed as conventional.
- 0 linked issue(s) detected in commits.
- 1430 day(s) passed between releases.

## 1.0.1 - 2021-07-18

### Miscellaneous Tasks

- Add release script

### Refactor

- Expose string functions

### Commit Statistics

- 2 commit(s) contributed to the release.
- 0 day(s) passed between the first and last commit.
- 2 commit(s) parsed as conventional.
- 0 linked issue(s) detected in commits.

## 1.0.0 - 2021-07-18

### Bug Fixes

- Rename help argument due to conflict

### Documentation

- Add README.md
- Add tested usage example

### Features

- Add ability to parse arrays

### Other (unconventional)

- Initial commit

### Commit Statistics

- 5 commit(s) contributed to the release.
- 4 day(s) passed between the first and last commit.
- 4 commit(s) parsed as conventional.
- 0 linked issue(s) detected in commits.

<!-- generated by git-cliff -->

Key Takeaways

Template Features Demonstrated

  1. Variable usage - {{ version }}, {{ timestamp }}, {{ commit.message }}
  2. Conditionals - {% if version %}...{% else %}...{% endif %}
  3. Loops - {% for group, commits in commits | group_by(attribute="group") %}
  4. Filters - | upper_first, | trim_start_matches, | date(format="...")
  5. Macros - {% macro print_commit(commit) %}...{% endmacro %}
  6. Nested grouping - Group by type, then by scope
  7. Statistics - Access commit metrics and metadata
  8. Remote integration - GitHub URLs and contributor info

Common Patterns

Version header with comparison link:
{% if previous.version %}
    ## [{{ version }}](https://github.com/owner/repo/compare/{{ previous.version }}..{{ version }})
{% else %}
    ## [{{ version }}]
{% endif %}
Group commits by type:
{% for group, commits in commits | group_by(attribute="group") %}
    ### {{ group | upper_first }}
    {% for commit in commits %}
        - {{ commit.message }}
    {% endfor %}
{% endfor %}
Include scope inline:
- {% if commit.scope %}*({{ commit.scope }})* {% endif %}{{ commit.message }}
Format dates:
{{ timestamp | date(format="%Y-%m-%d") }}

More Examples

Explore additional templates in the git-cliff examples directory:
  • github.toml - GitHub release format
  • cocogitto.toml - Cocogitto-style changelog
  • minimal.toml - Minimal, compact format
  • unconventional.toml - Non-conventional commits

Next Steps

Build docs developers (and LLMs) love