Skip to main content

What's new in 2.14.2? 🆕

· 3 min read
Orhun Parmaksız
Author of git-cliff

git-cliff is a command-line tool that provides a highly customizable way to generate changelogs from the Git history.


What's new? ⛰️​

This release mainly restores the npm and PyPI packages, alongside a few parser and CLI improvements.

The full changelog can be found here.


📦 npm & PyPI Packages​

The packages for v2.14.1 were not published to these registries due to an expired npm token interrupting the release workflow. v2.14.2 restores both distribution channels, so the latest version of git-cliff is available again on npm and PyPI 🥳

npm install git-cliff
pip install git-cliff

🧩 Multiple Commit Parsers​

Multiple commit parsers can now be applied to a single commit, allowing for more complex grouping and scoping rules!

Set continue = true on a parser to keep evaluating the parsers that follow it.

For example, a commit footer can set the scope before another parser assigns its group from the conventional commit type:

[git]
commit_parsers = [
{ footer = "^Component:Billing$", scope = "billing", continue = true },
{ footer = "^Component:Auth$", scope = "auth", continue = true },
{ message = "^feat", group = "Features" },
{ message = "^fix", group = "Bug Fixes" },
]

Given commits with Component: Billing and Component: Auth footers, this can produce:

### Bug Fixes

- (billing) correct totals rounding

### Features

- (billing) add invoices
- (auth) add login page

✅ Match Every Commit Parser Field​

When a commit parser defines multiple matching fields, all of them must now match before the parser is applied.

[git]
commit_parsers = [
{ message = "^feat:.*?(remove|delete|drop)", footer = "^BREAKING CHANGE:", group = "Removed" },
{ message = "^feat", group = "Added" },
{ message = "^fix", group = "Fixed" },
]

In the example above, a commit must match both the message and footer patterns to be grouped under "Removed". Previously, a commit matching either field would have been grouped under "Removed".


📁 Reliable --workdir Filtering​

Using --workdir could previously produce an empty changelog because its derived include pattern did not match Git's repository-relative paths. The working directory is now resolved relative to the repository root before filtering commits.

# Generate a changelog scoped to a subdirectory
git cliff --workdir ./crates/my-crate

# Generate a changelog for the entire repository
git cliff --workdir .

When the working directory is the repository root, no path filter is added, ensuring all relevant commits are retained, including commits without file changes.


❤️ New Contributors​

  • @heaths made their first contribution in #1641
  • @Jorge-Polanco-Roque made their first contribution in #1627
  • @genx7up made their first contribution in #1632
  • @sisp made their first contribution in #1616

Any contribution is highly appreciated! See the contribution guidelines for getting started.
Feel free to submit issues and join our Discord / Matrix for discussion!
Follow git-cliff on X & Mastodon to not miss any news!

Support 🌟​

If you like git-cliff, consider:

Have a fantastic day! ⛰️

What's new in 2.14.0?

· 10 min read
Orhun Parmaksız
Author of git-cliff

git-cliff is a command-line tool that provides a highly customizable way to generate changelogs from the Git history.


What's new? ⛰️​

So many things...

The full changelog can be found here.


⚠️ Migration Guide​

If you pass multiple values to --include-path, --exclude-path, --with-commit, or --skip-commit: you need to repeat the option for each value:

- git cliff --include-path "src/**" "docs/**"
+ git cliff --include-path "src/**" --include-path "docs/**"
For Rust API users 🦀
  • Opt::config is now an Option<PathBuf>. The public changelog and remote context types also gained fields, so code constructing them with struct literals must initialize the new fields.
  • git-cliff-core now uses git2 0.21. If you use git2 types exposed by its public API, update your git2 dependency as well.
For packagers 📦
  • Building git-cliff from source now requires Rust 1.88.0 or newer.
  • The upgrade to git2 0.21 includes a libgit2 SONAME change. Dynamically linked packages must be rebuilt against the new libgit2 version.

💻 CLI​

  • Smarter config discovery: when --config is omitted, git-cliff automatically looks for a configuration file. (#1584)

  • Custom templates: you can now keep your own configuration templates in a directory and initialize them by name with --init.

    Use --templates-dir (or GIT_CLIFF_TEMPLATES_DIR) to set the directory and --list-templates to see all built-in and custom templates. (#1583)

    $ tree ~/my-templates
    ~/my-templates
    ├── company.toml
    └── minimal.toml

    $ git cliff --templates-dir ~/my-templates --init company

    $ git cliff --list-templates --templates-dir ~/my-templates
    azure-devops-keepachangelog
    cocogitto
    company
    ...
  • Templates from files: you can now place your changelog body template in a file and load it with --body-file, making multiline templates easier to manage than passing them directly with --body. (#1574)

    $ git cliff --body-file changelog-body.tera
  • Safer multi-value arguments: path and commit options now consume one value per occurrence, preventing a trailing positional range from being mistaken for another option value. (#1614)

    # Repeat the option for each path
    $ git cliff --include-path "src/**" --include-path "docs/**" v1.0.0..v2.0.0

    # Or pass path patterns as one quoted, space-delimited value
    $ git cliff --include-path "src/** docs/**" v1.0.0..v2.0.0

    # The positional range can also come first
    $ git cliff v1.0.0..v2.0.0 --include-path "src/**" --include-path "docs/**"

🧩 Templating​

  • git-cliff can now format markdown! (#1610)

    It is opt-in and can be enabled via the format option:

    [changelog]
    format = true
    info

    Formatting normalizes headings, list markers and excessive blank lines. It supports GitHub-flavored Markdown features such as tables, strikethrough, task lists and footnotes and only runs for stdout, extension-less paths and .md output.

    Ambiguous bare brackets such as [unreleased] are escaped according to CommonMark rules.

  • New filters: two new filters give you more control over how releases and commits are grouped:

    • commit_groups preserves first appearance order or follows the order of commit_parsers_groups. (#1518)

      tip

      If you were using numbered HTML comments to control the group order, you can now remove them:

      commit_parsers = [
      - { message = "^feat", group = "<!-- 0 -->Features" },
      - { message = "^fix", group = "<!-- 1 -->Bug Fixes" },
      + { message = "^feat", group = "Features" },
      + { message = "^fix", group = "Bug Fixes" },
      ]

      Then replace the group_by loop with commit_groups(groups=commit_parsers_groups):

      -{% for group, commits in commits | group_by(attribute="group") %}
      - ### {{ group | striptags | trim | upper_first }}
      - {% for commit in commits %}- {{ commit.message }}
      +{% for entry in commits | commit_groups(groups=commit_parsers_groups) %}
      + ### {{ entry.group | trim | upper_first }}
      + {% for commit in entry.commits %}- {{ commit.message }}
      {% endfor %}
      {% endfor %}

      Each returned entry contains the group name in entry.group and its commits in entry.commits.

      striptags is no longer needed either.

    • group_by_scope groups releases at a chosen semantic-version scope such as major, minor, or patch, with support for version prefixes. (#1547)

      {% for version, releases in releases | group_by_scope(scope="minor", prefix="v") %}
      ## {{ version }}
      {% for release in releases %}
      - {{ release.version }}
      {% endfor %}
      {% endfor %}

      Releases v0.1.0, v0.1.1 and v0.2.0 render as:

      ## v0.1

      - v0.1.1
      - v0.1.0

      ## v0.2

      - v0.2.0
  • New variables: remote metadata now exposes more information for changelog templates:

    • commit.remote.pr_author contains the author of the matched pull request. (#1613)

      {
      "commits": [
      {
      "remote": {
      "username": "merge-maintainer",
      "pr_author": "pull-request-author",
      "pr_number": 42
      }
      }
      ]
      }
      info

      pr_author is more reliable than resolving the commit author's email for squash merges, where username can point to the maintainer who merged the change.

    • [github|gitlab|etc].contributors[].pr_numbers contains every pull request attributed to a contributor in the release, sorted by number. The existing pr_number field remains available for compatibility. (#1546)

      {
      "github": {
      "contributors": [
      {
      "username": "contributor",
      "pr_number": 42,
      "pr_numbers": [42, 57, 81]
      }
      ]
      }
      }
  • Built-in GitLab templates: (#1561)

    • gitlab generates concise release notes with merge request, contributor and tag links:

      $ git cliff --config gitlab
    • gitlab-keepachangelog generates a more detailed Keep a Changelog layout with GitLab commit and merge request links:

      $ git cliff --config gitlab-keepachangelog

    You can also use either preset as the starting point for your own configuration:

    $ git cliff --init gitlab-keepachangelog

⚙️ Configuration​

  • Skip version bumps for selected commits: different commit types can now be excluded from version bump calculations with no_increment_regex. (#1522)

    [bump]
    no_increment_regex = "chore|ci|docs"
  • Configure remote request timeouts: remote metadata requests now have a configurable http_timeout. (#1580)

    [remote.github]
    http_timeout = "60s"
  • Better prepend support: the new header_marker tells git-cliff where the header ends, so it can remove the old header before writing the new one. (#1603)

    [changelog]
    header = """
    # Changelog

    Tracked releases: {{ releases | length }}
    """
    header_marker = "<!-- git-cliff: end of header -->"

    Then prepend a new release as usual:

    $ git cliff --unreleased --prepend CHANGELOG.md

    The marker is written automatically after the rendered header:

    # Changelog

    Tracked releases: 1

    <!-- git-cliff: end of header -->

    ## Unreleased

    On the next --prepend, git-cliff removes everything through the marker before writing the updated header.

  • Configuration schema: the git-cliff configuration schema is now available on SchemaStore, enabling validation and autocompletion in supported editors. (#1577)

    tip

    To select it explicitly in a Taplo-compatible editor, add this directive at the top of your configuration:

    cliff.toml
    #:schema https://www.schemastore.org/git-cliff.json

🌳 Git​

  • Correct releases across merged branches: commits are now assigned to releases using Git graph reachability. (#1601)

    Why this is big?

    Consider a feature branch that splits before v1.0.0 but is merged afterward:

              F---G
    / \
    A---B---C---D---M main
    |
    v1.0.0

    F and G are not part of v1.0.0. However, a flattened git log can interleave commits from both branches and make them look like they belong to that release.

    git-cliff now checks the actual commit graph instead. In this example, F and G stay under Unreleased until they are included in a later tag.

    This fixes changelogs that list changes under a release that never shipped them, omit those changes from Unreleased or disagree with the actual previous_tag..tag history. It is especially useful for repositories with long-lived release branches, backports or branches that are merged after a release.

  • Limit processed tags: (#1493)

    $ git cliff --limit-tags 10

    You can also set limit_tags in your configuration:

    [git]
    limit_tags = 10
  • Nested annotated tags: tags that point to other annotated tags are peeled all the way to their commit and are no longer silently omitted. (#1360)

  • Respect commits listed in .git-blame-ignore-revs: they are now automatically excluded from the changelog. (#1585)

    .git-blame-ignore-revs
    # Mass formatting
    67b8f240063d0d5b8f6c58be198d31e36fbf251a

⚡ Performance​

Commit statistics are no longer calculated unless a template, parser, or --context output actually needs them. This avoids walking every diff for changelogs that do not use statistics, significantly reducing unnecessary work on larger repositories. (#1543)


❤️ New Contributors​

Any contribution is highly appreciated! See the contribution guidelines for getting started.
Feel free to submit issues and join our Discord / Matrix for discussion!
Follow git-cliff on X & Mastodon to not miss any news!

Support 🌟​

If you like git-cliff, consider:

Have a fantastic day! ⛰️

What's new in 2.13.0?

· 5 min read
Orhun Parmaksız
Author of git-cliff

git-cliff is a command-line tool that provides a highly customizable way to generate changelogs from the Git history.


What's new? ⛰️​

The full changelog can be found here.


🔢 Configurable Processing Order​

git-cliff now supports defining your own pipeline of commit processing steps via processing_order configuration option!

[git]
processing_order = [
"commit_preprocessors",
"split_commits",
"conventional_commits",
"commit_parsers",
"link_parsers",
]

The available processing steps are:

info

This is useful for advanced users who want to have more control over the commit processing pipeline, for example, to run custom preprocessors before the conventional commit parsing step.


🌀 Migrate Logging to Tracing​

We now use the tracing crate for logging in git-cliff!

Before:

After:

Please let us know if you encounter any bugs or UX issues!


⚙️ Alternative Config Locations​

git-cliff now supports more configuration file locations!

  • cliff.toml
  • .cliff.toml
  • .config/cliff.toml
  • $HOME/cliff.toml
  • $HOME/.cliff.toml
  • $HOME/.config/cliff.toml

📊 Per-Commit Statistics​

You can now get per-commit statistics in the release context:

{% for commit in commits %}
- {{ commit.message }} ({{ commit.statistics.files_changed }} files, +{{ commit.statistics.additions }}, -{{ commit.statistics.deletions }})
{% endfor %}

Results in:

- Fix a bug (3 files, +10, -2)

The available statistics are:

  • {{ commit.statistics.files_changed }}: Number of files changed in the commit
  • {{ commit.statistics.additions }}: Number of lines added in the commit
  • {{ commit.statistics.deletions }}: Number of lines deleted in the commit

🏷️ Bump Type in Context​

The determined bump type is now available in the release context as {{ bump_type }}. This can be used to conditionally render content based on the bump type, for example:

{% if bump_type == "major" %}
- This is a major release!
{% endif %}

The available bump types are major, minor and patch.


📡 Environment Variable for Offline​

You can now also set the GIT_CLIFF_OFFLINE environment variable to execute in offline mode:

$ GIT_CLIFF_OFFLINE=true git-cliff

Is the same as:

[remote]
offline = false

Or passing the --offline flag.


🐋 Docker Tag Updates​

There were some updates to the Docker tags pushed from the CI:

  • latest: only on version tag builds
  • main: only on pushes to the main branch
  • sha-<short>: commit SHA builds (e.g. sha-954106f)
  • X.Y.Z: SemVer tag derived from Git tag (e.g. 2.13.0)

e.g. to pull the latest stable version, you can now use:

$ docker pull orhun/git-cliff:latest

🧰 Other​

  • (lib) Raise MSRV to 1.87.0 (#1479) - (9b38cb4)
  • (args) Correctly parse multiple env values for include/exclude paths (#1450) - (f1874b8)
  • (cli) Warn when --with-commit does not change version (#1484) - (3d6a7cb)
  • (remote) Deserialize GitLab API data models safely (#1368) - (954106f)
  • (docker) Install ca-certificates in docker image (#1425) - (1732b9a)
  • (cd) Publish musl wheels to PyPI by matching matrix.build.NAME (#1490) - (9b5e732)

New Contributors ❤️​

  • @truffle-dev made their first contribution in #1490
  • @WaterWhisperer made their first contribution in #1487
  • @ChihebBENCHEIKH1 made their first contribution in #1483
  • @sermuns made their first contribution in #1486
  • @danielpza made their first contribution in #1448
  • @niklasmarderx made their first contribution in #1456
  • @lawrence3699 made their first contribution in #1484
  • @mixator made their first contribution in #1392
  • @saudademjj made their first contribution in #1450
  • @nbelsterling made their first contribution in #1425
  • @y5 made their first contribution in #1427
  • @Garbee made their first contribution in #1371

Any contribution is highly appreciated! See the contribution guidelines for getting started.

Feel free to submit issues and join our Discord / Matrix for discussion!

Follow git-cliff on Twitter & Mastodon to not miss any news!

Support 🌟​

If you liked git-cliff and/or my other projects on GitHub, consider donating to support my open source endeavors.

Have a fantastic day! ⛰️

What's new in 2.12.0?

· 3 min read
Orhun Parmaksız
Author of git-cliff

git-cliff is a command-line tool that provides a highly customizable way to generate changelogs from the Git history.


What's new? ⛰️​

The full changelog can be found here.


📡 Offline Mode​

Now you can run git-cliff in offline mode using the --offline flag!

This feature disables contacting any external services, even if they are configured. This can be useful in scenarios where you want to avoid network calls or when working in a restricted environment.

$ git cliff --offline

This can be also configured as a part of the the remote configuration, for example:

[remote.gitlab]
owner = "archlinux"
repo = "arch-repro-status"
offline = true

⏩ Skip Tags via CLI​

Skipping certain tags with regex was already possible via the configuration file:

[git]
skip_tags = "beta|alpha"

Now you can also specify the same via the command-line using the --skip-tags argument:

$ git cliff --skip-tags "beta|alpha"

↩️ Revert Log Verbosity​

A couple of users reported the new verbosity level introduced in 2.11.0 was too noisy for their use cases.

With this release, we reverted that change and started exploring alternative ways to provide more detailed logs in a less-overwhelming way.

Related issues: #1352, #1354, #1327


🌀 Rename Azure DevOps variable​

⚠️ This is a breaking change for those using Azure DevOps remote integration.

In your template, rename {{ azureDevops.contributors }} to {{ azure_devops.contributors }}.

- {% for contributor in azureDevops.contributors | filter(attribute="is_first_time", value=true) %}
+ {% for contributor in azure_devops.contributors | filter(attribute="is_first_time", value=true) %}

See #1318 for the rationale behind this change.


🧰 Other​

  • (config) Respect the changelog.output configuration (#1349) - (cfcc5ae)
  • (remote) Avoid false first-time contributors when tag timestamp missing (#1348) - (de7cf02)
  • (remote) Remove reqwest::Response::error_for_status (#1336) - (081ba68)

New Contributors ❤️​

  • @taladar made their first contribution in #1319
  • @barskern made their first contribution in #1321
  • @ooooo-create made their first contribution in #1334
  • @jylenhof made their first contribution in #1320

Any contribution is highly appreciated! See the contribution guidelines for getting started.

Feel free to submit issues and join our Discord / Matrix for discussion!

Follow git-cliff on Twitter & Mastodon to not miss any news!

Support 🌟​

If you liked git-cliff and/or my other projects on GitHub, consider donating to support my open source endeavors.

Have a fantastic day! ⛰️

What's new in 2.11.0?

· 5 min read
Orhun Parmaksız
Author of git-cliff

git-cliff is a command-line tool that provides a highly customizable way to generate changelogs from the Git history.


What's new? ⛰️​

The full changelog can be found here.

Happy new year!

This is going to be the last release of 2025!

Wishing you all a fantastic new year ahead filled with Git commits, automated changelogs and cliff jumps! 🎄⛰️


🌀 Azure DevOps Integration​

git-cliff now supports Azure Devops for remote integration, enabling changelog generation with metadata from Azure DevOps repositories (commits, pull requests, and contributors). 🥳

Simply configure your cliff.toml for your own repository as follows:

# Azure DevOps integration for fetching commit metadata.
[remote.azure_devops]
owner = "shiftme/gitcliff"
repo = "git-cliff-readme-example"

And then update your [changelog].body with the relevant template variables, e.g. {{ commit.remote.pr_number }}, {{ commit.remote.username }} and so on.

e.g. results in:

## What's Changed in v1.0.0

- Initial commit by @orhun
- docs(project): add README.md by @orhun
- feat(parser): add ability to parse arrays by @orhun
- fix(args): rename help argument due to conflict by @orhun
- docs(example)!: add tested usage example by @orhun

### New Contributors

- @orhun made their first contribution

For more information, see the documentation.

Thanks to @amd989 for the implementation in #1283!


❎ Failing on unmatched commits​

A new configuration variable was added for enforcing that all commits are matched by a commit parser:

[git]
commit_parsers = [
{ message = "^feat", group = "Should be matched" },
]

fail_on_unmatched_commit = true

If fail_on_unmatched_commit is set to true, git-cliff will fail when any commit included in the changelog is not matched by any of the configured commit_parsers.


🧩 New built-in filters​

git-cliff now has new custom filters you can use inside templates:

  • upper_first: Converts the first character of a string to uppercase.

      {{ "hello" | upper_first }} →  Hello
  • find_regex: Finds all occurrences of a regex pattern in a string.

    {{ "hello world, hello universe" | find_regex(pat="hello") }} →  [hello, hello]
  • replace_regex: Replaces all occurrences of a regex pattern with a string.

    {{ "hello world" | replace_regex(from="o", to="a") }} →  hella warld
  • split_regex: Splits a string by a regex pattern.

    {{ "hello world, hello universe" | split_regex(pat=" ") }} →  [hello, world,, hello, universe]

🆙 Increased log verbosity​

We have evaluated and increased the verbosity of some log messages to provide better insights into the internal workings of git-cliff.

To get more detailed logs, provide one or multiple -v flags when running:

$ git cliff -vv

✨ Better include-path handling​

  1. The --include_path's behavior has been revised and several reported issues have been addressed in #1290 thanks to @ognis1205!

  2. --include-path is now automatically set to the value of --workdir if the latter is provided. This ensures that commit parsing works as expected when a different working directory is specified.

Before:

git cliff --workdir my_crate --include-path my_crate

After:

git cliff --workdir my_crate


🦀 Better API​

The git-cliff library crates (git_cliff & git_cliff_core) has been improved with several new features and enhancements!

  • git_cliff::run now returns the generated git_cliff_core::changelog::Changelog,
  • git_cliff::write_changelog helper writes it to a file or stdout,
  • git_cliff::init_config function handles config creation,
  • git_cliff::check_new_version is now public.

Breaking changes:

  • Changelog::new / Changelog::from_context take Config by value

Here is how you can create a minimal git-cliff application in Rust:

use clap::Parser;
use git_cliff::args::Opt;
use git_cliff_core::error::Result;

fn main() -> Result<()> {
let args = Opt::parse();
let changelog = git_cliff::run(args.clone())?;
git_cliff::write_changelog(&args, changelog, std::io::stdout())?;
Ok(())
}

🧰 Other​

  • (bump) Write bumped version to stdout even when output config is set (#1307) - (314ff57)
  • (args) Group remote-related CLI arguments under REMOTE OPTIONS heading (#1271) - (0b6af12)
  • (remote) Expose commits and PRs as streams (#1272) - (b82221a)
  • (ci) Stabilize lychee link checking in CI (#1295) - (7ed1db0)

New Contributors ❤️​

  • @Lewiscowles1986 made their first contribution in #1226
  • @OpenSauce made their first contribution in #1314
  • @amd989 made their first contribution in #1283
  • @asweet-confluent made their first contribution in #1272
  • @linus-skold made their first contribution in #1287
  • @simoncdn made their first contribution in #1305
  • @haidaraM made their first contribution in #1285
  • @ritoban23 made their first contribution in #1271

Any contribution is highly appreciated! See the contribution guidelines for getting started.

Feel free to submit issues and join our Discord / Matrix for discussion!

Follow git-cliff on Twitter & Mastodon to not miss any news!

Support 🌟​

If you liked git-cliff and/or my other projects on GitHub, consider donating to support my open source endeavors.

Have a fantastic day! ⛰️

What's new in 2.10.0?

· 6 min read
Orhun Parmaksız
Author of git-cliff

git-cliff is a command-line tool that provides a highly customizable way to generate changelogs from the Git history.


What's new? ⛰️​

The full changelog can be found here.


📈 Release statistics​

git-cliff now supports adding various release-related metrics to the changelog via statistics variable!

You can use it in your template as follows:

[changelog]
body = """
### 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.

{%- for link in statistics.links %}
{{ " " }}- [{{ link.text }}]({{ link.href }}) (referenced {{ link.count }} time(s))
{%- endfor %}

- {{ statistics.days_passed_since_last_release }} day(s) passed between releases.

"""

This will render a section like this in the changelog:

## Commit Statistics

- 5 commit(s) contributed to the release.
- 0 day(s) passed between the first and last commit.
- 5 commit(s) parsed as conventional.
- 3 linked issue(s) detected in commits.
- [#452](https://github.com/orhun/git-cliff/issues/452) (referenced 2 time(s))
- [#1148](https://github.com/orhun/git-cliff/issues/1148) (referenced 1 time(s))
- [ietf-rfc3986](https://datatracker.ietf.org/doc/html/rfc3986) (referenced 1 time(s))
- 1430 day(s) passed between releases.

See release statistics for the available variables and more details.

Thanks to Shingo OKAWA for the implementation in #1151!


📝 New template​

Related to the new statistics feature, we added a new built-in template called statistics.toml!

It can be used as follows:

$ git cliff --config statistics

To initialize cliff.toml with it:

$ git cliff --init statistics

INFO git_cliff > Saving the configuration file (statistics) to "cliff.toml"

It serves the purpose of providing a basic template that includes release statistics. You can use it as a starting point for your own changelog template or simply use it as is.


📁 Include/exclude paths in config​

As highly requested, you can now include or exclude specific paths in your changelog generation via the include_paths and exclude_paths options in the configuration file.

[git]
include_paths = ["src/", "doc/**/*.md"]
exclude_paths = ["unrelated/"]

These options are the same as providing --include-paths and --exclude-paths command line arguments.

Thanks to @Kriskras99 for implementing this in #1173!


🧮 Support matching arrays via parsers​

The commit parser has been extended to support regex matching on array values, such as remote.pr_labels.

For example, this makes it possible to group commits based on their GitHub labels as follows:

[git]
commit_parsers = [
{ field = "remote.pr_labels", pattern = "duplicate|invalid|wontfix|skip changelog", skip = true },
{ field = "remote.pr_labels", pattern = "breaking change", group = "<!-- 0 -->🏗️ Breaking Changes" },
{ field = "remote.pr_labels", pattern = "feature|deprecation", group = "<!-- 1 -->🚀 Features" },
{ field = "remote.pr_labels", pattern = "enhancement|refactor", group = "<!-- 1 -->🛠️ Enhancements" },
{ field = "remote.pr_labels", pattern = "bug|regression", group = "<!-- 2 -->🐛 Bug Fixes" },
{ field = "remote.pr_labels", pattern = "security", group = "<!-- 3 -->🔐 Security" },
{ field = "remote.pr_labels", pattern = "documentation", group = "<!-- 4 -->📝 Documentation" },
{ message = ".*", group = "<!-- 5 -->🌀 Miscellaneous" },
]

🗑️ Empty header/footer as default​

In the previous release, we internally started initializing the configuration file with default values. This sadly made it impossible to render a changelog without a header or footer.

This behavior has been reverted in this release and the default values for [changelog.header] and [changelog.footer] are now empty. Meaning that the following is a minimal configuration that will render a changelog without a header or footer:

[changelog]
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 %}\
- {% if commit.breaking %}[**breaking**] {% endif %}{{ commit.message | upper_first }}
{% endfor %}\
{% endfor %}\n
"""

🐧 Gentoo support​

git-cliff made its way into the Gentoo Linux package repository! 🎉

It can be installed via the following command:

emerge git-cliff

See the package page here.

Thanks to @aspann for packaging!


🏴 Spaces instead of tabs​

git-cliff now uses spaces instead of tabs throughout the codebase! This change made the code more consistent with the Rust community's conventions and improved readability.

Fun Fact

Hard tabs are used in around 0.1% of Rust projects. I don't know why I went with that config option when I first started this project. I guess I was a rebel back then.


🧰 Other​

  • (config) Check if commit.footers is defined in detailed example (#1170) - (078545f)
  • (generation) Ensure skip_tags condition is evaluated first (#1190) - (318be66)
  • (repo) Use the correct order while diffing paths (#1188) - (ff6c310)
  • (config) Implement FromStr instead of Config::parse_from_str() (#1185) - (692345e)
  • (ci) Apply security best practices (#1180) - (a32deca)
  • (fixture) Add test fixture for overriding the conventional scope (#1166) - (cb84a08)
  • (build) Bump MSRV to 1.85.1 - (d8279d4)
  • (crate) Remove Rust nightly requirement - (4f3e5af)

New Contributors ❤️​

  • @Nick2bad4u made their first contribution in #1180
  • @aspann made their first contribution in #1203
  • @muzimuzhi made their first contribution in #1200
  • @j-g00da made their first contribution in #1188
  • @Kriskras99 made their first contribution in #1173
  • @wetneb made their first contribution in #1165
  • @gmeligio made their first contribution in #1170
  • @LitoMore made their first contribution in #1164

Any contribution is highly appreciated! See the contribution guidelines for getting started.

Feel free to submit issues and join our Discord / Matrix for discussion!

Follow git-cliff on Twitter & Mastodon to not miss any news!

Support 🌟​

If you liked git-cliff and/or my other projects on GitHub, consider donating to support my open source endeavors.

Have a fantastic day! ⛰️

What's new in 2.9.0?

· 7 min read
Orhun Parmaksız
Author of git-cliff

git-cliff is a command-line tool that provides a highly customizable way to generate changelogs from the Git history.


10k Stars! 🌟​

Started from the cd69e764f68e5f09cf6e14975e6a876cdccbcfb9, now we're here.

Click here for the star history

star history

git-cliff has reached a whopping 10000 stars on GitHub and I wanted to celebrate this huge milestone with giving away a limited edition T-shirt!

giveaway

You can join the giveaway by clicking here. Nothing else is required!

If you want to buy the T-shirt and support the project, visit our shop at Grindhouse for different sizes and colors!

Thank you all for the support and love you have shown to git-cliff! ⛰️🧡


What's new? ⛰️​

The full changelog can be found here.


🌀 Submodule Support​

git-cliff now supports submodules! You can recurse into submodules and generate changelogs for them as well.

Just set the following option in your configuration file:

[git]
recurse_submodules = true

And then you can use the submodule_commits template variable to access the commits of submodules as follows:

[changelog]
body = """
{% for submodule_path, commits in submodule_commits %}
### {{ submodule_path | upper_first }}
{% for group, commits in commits | group_by(attribute="group") %}
#### {{ group | upper_first }}
{% for commit in commits %}
- {{ commit.message | upper_first }}\
{% endfor %}
{% endfor %}
{% endfor %}\n
"""

Thanks @lehmanju for the implementation in #1082!


⚠️ Conventional commit check​

git-cliff can now check if the commits in the repository follow the conventional commits specification.

To enable this check, set the require_conventional option in your configuration file:

[git]
require_conventional = true

If any unconventional commits are found, an error will be thrown and the changelog generation will fail.


🛰️ Remote config​

Have a configuration file elsewhere on the internet? No probs.

$ git cliff --config-url https://github.com/orhun/git-cliff/blob/main/examples/github-keepachangelog.toml?raw=true

The new --config-url option allows you to specify a URL to a configuration file!


↔️ Commit range variable​

The template context now includes a commit_range variable that contains the range of commits that were used to generate the changelog.

Can be used as follows:

{{ commit_range.from }}..{{ commit_range.to }}

Results in:

a140cef0405e0bcbfb5de44ff59e091527d91b38..a9d4050212a18f6b3bd76e2e41fbb9045d268b80
tip

You can use the truncate filter to shorten the commit range:

{{ commit_range.from | truncate(length=7, end="") }}..{{ commit_range.to | truncate(length=7, end="") }}

Results in:

a140cef..a9d4050

🌿 Better branch support​

git-cliff used to only support the default branches of the remotes (e.g., main branch on GitHub).

Now, it can fetch commits from the correct branch automatically based on the commit range that you provide.

For example:

$ git cliff v1.0.0..v1.0.1 --github-repo my-org/my-private-repo

This command used to default to the main branch of the my-org/my-private-repo repository. Now, it will use the v1.1 branch thus using the correct commits for the changelog.

Similarly:

$ git cliff 9f66ac0f76..89de5e8e50 --gitlab-repo my-org/my-private-repo

The changelog will contains commits up to the commit 89de5e8e50.

Thanks to @william-stacken for the implementation in #1086!


🔢 Disable topological sorting​

The topological sorting of commits can now be disabled by setting the topological_sort option to false in your configuration file:

[git]
topo_order_commits = false
  • If false, the commits will be sorted in the order they were committed, without considering their parent-child relationships.
    • This is equivalent to running git log.
  • Otherwise, if true (default), the commits will be sorted topologically, which means that the commits will be ordered in such a way that all parent commits come before their children.
    • This is equivalent to running git log --topo-order.

📝 New blog posts​

Check out the new blog posts from the community members:


🛡️ Remove tj-actions​

There was a security issue reported in the tj-actions organization.

There is also a GitHub Action created for git-cliff: tj-actions/git-cliff.

The action seems to be unaffected by the compromise, but I have removed all the references to it from the documentation and the website for safety.


🐛 Various Bug Fixes​

  • (bump) Check the next version against tag_pattern regex (#1070) - (c4f0d28)
  • (bump) Accept lowercase values for bump_type config (#1101) - (77632b2)
  • (git) Handle worktrees while retrieving the path of repository (#1054) - (fab02b0)
  • (remote) Fix detection of GitLab merge request sha if commits were squashed (#1043) - (5f3a3d0)
  • (submodules) Fix submodules handling when using custom range (#1136) - (451a694)
  • (template) Correctly serialize JSON for the commit fields (#1145) - (e981e1d)

🧰 Other​

  • (project) Migrate to Rust 2024 edition (#1128) - (4445f06)
  • (config) Initialize config structs with default values (#1090) - (9e4bd07)
  • (quickstart) Clarify git-cliff command (#1051) - (cd26bb2)
  • (security) Extend security policy (#1142) - (4c3c946)

New Contributors ❤️​

  • @ognis1205 made their first contribution in #1145
  • @janderssonse made their first contribution in #1142
  • @jdrst made their first contribution in #1138
  • @lehmanju made their first contribution in #1136
  • @Jean-Beru made their first contribution in #1132
  • @william-stacken made their first contribution in #1086
  • @SebClapie made their first contribution in #1121
  • @okydk made their first contribution in #1051

Any contribution is highly appreciated! See the contribution guidelines for getting started.

Feel free to submit issues and join our Discord / Matrix for discussion!

Follow git-cliff on Twitter & Mastodon to not miss any news!

Support 🌟​

If you liked git-cliff and/or my other projects on GitHub, consider donating to support my open source endeavors.

Have a fantastic day! ⛰️

What's new in 2.8.0?

· 4 min read
Orhun Parmaksız
Author of git-cliff

git-cliff is a command-line tool (written in Rust) that provides a highly customizable way to generate changelogs from git history.

It supports using custom regular expressions to alter changelogs which are mostly based on conventional commits. With a single configuration file, a wide variety of formats can be applied for a changelog, thanks to the Jinja2/Django-inspired template engine.

More information and examples can be found in the GitHub repository.

What's new? ⛰️​

Happy new year! This version of git-cliff comes with quality of life improvements and bug fixes.

The full changelog can be found here.


🔥 Improved Monorepo Support​

There were numerous improvements to the monorepo support in this release:

  1. git-cliff now discovers the Git repositories automatically even though when you run from sub directories.

  2. The configuration file is now automatically found when running from a sub directory.

  3. The include-path is now automatically set to the current directory when running from a sub directory.

As a result, the following command:

$ cd packages/some_library

$ git cliff --include-path "packages/some_library/**/*" --repository "../../"

becomes:

$ cd packages/some_library

$ git cliff # just works!

🛡️ Native TLS Support​

git-cliff now supports enabling native TLS for remote requests. This is useful when you rely on a corporate trust root (e.g., for a mandatory proxy) that's included in your system's certificate store.

To enable it:

$ git cliff --use-native-tls

Or configure it in your cliff.toml:

[remote.gitlab]
owner = "archlinux"
repo = "arch-repro-status"
api_url = "https://gitlab.archlinux.org/api/v4"
native_tls = true

⚙️ Custom Config Name​

You can now specify a custom filename for the configuration while initializing git-cliff:

$ git-cliff --init --config custom.toml

🚨 Better Errors​

Before:

$ git cliff test
ERROR git_cliff > Git error: `unable to parse OID - contains invalid characters; class=Invalid (3)`

After:

$ git cliff test
ERROR git_cliff > Failed to set the commit range: unable to parse OID - contains invalid characters; class=Invalid (3)
"test" is not a valid commit range. Did you provide the correct arguments?

🔄 Run with Callback API​

If you are using git-cliff in your Rust project as a library, you can now run it with a callback function to modify the changelog before it's printed:

use clap::Parser;
use git_cliff::args::Opt;
use git_cliff_core::error::Result;

fn main() -> Result<()> {
let args = Opt::parse();

git_cliff::run_with_changelog_modifier(args, |changelog| {
println!("Releases: {:?}", changelog.releases);
Ok(())
})?;

Ok(())
}

🧰 Other​

  • (config) Allow environment overwrites when using builtin config (#961) - (7ba3b55)
  • (remote) Fix detection of GitLab merge request sha (#968) - (1297655)
  • (tips) Extend the merge commit filter example (#963) - (09c0f90)
  • (build) Bump MSRV to 1.83.0 - (37598c2)

Contributions 👥​

  • @xsadia made their first contribution in #992
  • @chenrui333 made their first contribution in #1002
  • @hackenbergstefan made their first contribution in #968
  • @paul-uz made their first contribution in #963
  • @jmartens made their first contribution in #959

Any contribution is highly appreciated! See the contribution guidelines for getting started.

Feel free to submit issues and join our Discord / Matrix for discussion!

Follow git-cliff on Twitter & Mastodon to not miss any news!

Support 🌟​

If you liked git-cliff and/or my other projects on GitHub, consider donating to support my open source endeavors.

Have a fantastic day! ⛰️

What's new in 2.7.0?

· 6 min read
Orhun Parmaksız
Author of git-cliff

git-cliff is a command-line tool (written in Rust) that provides a highly customizable way to generate changelogs from git history.

It supports using custom regular expressions to alter changelogs which are mostly based on conventional commits. With a single configuration file, a wide variety of formats can be applied for a changelog, thanks to the Jinja2/Django-inspired template engine.

More information and examples can be found in the GitHub repository.

What's new? ⛰️​

The full changelog can be found here.


🥋 Jujutsu Support​

git-cliff now supports opening a repository that has been cloned using Jujutsu!

For example:

$ jj git clone --colocate https://github.com/orhun/git-cliff

$ cd git-cliff

$ git cliff # works!
caution

This works differently with colocated and non-colocated repositories. See the documentation for more information.

tip

Watch my first live reaction to Jujutsu on this stream: Learning Jujutsu (a version control system)


☘️ Add missing fields to context​

A bug causing some fields such as footer to be missing in the context JSON has been fixed.

This means that the following command now yields an identical result with git-cliff:

# hey look, a snake eating its own tail! 🐍
git cliff --context | git cliff --from-context

📩 Raw message in context​

The context now contains the raw/unprocessed full commit message in the raw_message field. For example:

{
"version": "v0.1.0-rc.21",
"message": "The annotated tag message for the release",
"commits": [
{
"raw_message": "<type>[scope]: <description>\n[body]\n[footer(s)]"
}
]
}

You can use it like so:

{% for commit in commits %}
{{ commit.raw_message }}
{% endfor %}

⚙️ Remote API URL configuration​

In addition to the command-line/environment variables, you can now override the remote API URL in the configuration file as follows:

[remote.gitlab]
owner = "archlinux"
repo = "arch-repro-status"
api_url = "https://gitlab.archlinux.org/api/v4" # new!

This is useful when you have a self-hosted Git service and want to use the API for fetching metadata.

See the remote configuration for more information.


✨ Preserve first time contributors​

There was a bug causing the first time contributors to be removed from the changelog when there was a new release. This has been fixed and now the first time contributors are preserved in the changelog.

So if you run git cliff now, you might get new names in the changelog! Don't be surprised.

See this pull request for more details.


🐋 ARM Docker images​

We brought back the Docker images for ARM64! 🎉 See them here.

docker run --platform linux/arm64 -t -v "$(pwd)":/app/ "orhunp/git-cliff:${TAG:-latest}"

There was a problem building these images due to the timeouts in the GitHub Actions workflow. This turned out to be a problem related to needlessly fetching the Rust toolchain in the build step of cargo-chef and is now fixed in this pull request.

See the related discussion here.


❄️ Nix environment​

We now have a basic and reproducible dev environment using Nix along with CI checks for it!

Here is the Nix flake and you can use it by running nix build and nix run commands.


🎨 Colored help​

A small cosmetic change, but the output of git cliff --help is now colorful!

Try it for yourself :)


💖 User testimonials​

Do you like git-cliff? Spread the word on social media and let me know your thoughts! I will be featuring your testimonials.

I collected the testimonials that I could find so far and added them to the website. It picks one randomly on each page load.

Shoutout to those amazing people!


🚀 Stabilize remote integration​

The remote integration with GitHub/GitLab/Gitea/Bitbucket has been stabilized and now works as expected (apart from a couple of bugs that come and go occasionally).


🧰 Other​

  • (log) Add trace log about which command is being run - (a9b2690)
  • (bitbucket) Match PR and release metadata correctly (#907) - (e936ed5)
  • (changelog) Include the root commit when --latest is used with one tag (#901) - (508a97e)
  • (config) Add the 'other' parser to the default config - (12cb1df)
  • (git) Improve docs for commit_preprocessors and commit_parsers (#928) - (c1f1215)

Contributions 👥​

  • @pauliyobo made their first contribution in #896
  • @blackheaven made their first contribution in #939
  • @Muhammad-Owais-Warsi made their first contribution in #928
  • @kemitix made their first contribution in #930
  • @mcwarman made their first contribution in #925
  • @LtdSauce made their first contribution in #919
  • @dqkqd made their first contribution in #920
  • @gsquire made their first contribution in #909
  • @rarescosma made their first contribution in #901
  • @vsn4ik made their first contribution in #894

Any contribution is highly appreciated! See the contribution guidelines for getting started.

Feel free to submit issues and join our Discord / Matrix for discussion!

Follow git-cliff on Twitter & Mastodon to not miss any news!

Support 🌟​

If you liked git-cliff and/or my other projects on GitHub, consider donating to support my open source endeavors.

Have a fantastic day! ⛰️

What's new in 2.6.0?

· 4 min read
Orhun Parmaksız
Author of git-cliff

git-cliff is a command-line tool (written in Rust) that provides a highly customizable way to generate changelogs from git history.

It supports using custom regular expressions to alter changelogs which are mostly based on conventional commits. With a single configuration file, a wide variety of formats can be applied for a changelog, thanks to the Jinja2/Django-inspired template engine.

More information and examples can be found in the GitHub repository.

What's new? ⛰️​

The full changelog can be found here.


🛠️ Deprecated integration fields​

The following fields are deprecated and will be removed in the next releases:

  • commit.github, commit.gitea, commit.gitlab, commit.bitbucket

You can now use the commit.remote field instead. For example:

-{% if commit.github.username %}
+{% if commit.remote.username %}

🌲 Better branch support​

If you have diverged branches for your project and want to changelog for each branch, you can now use the --use-branch-tags option.

$ git cliff --use-branch-tags

The generated changelog above will only include the tags from the current branch.

Also, you can use it from the configuration file:

[git]
use_branch_tags = true
info

See the implementation for more explanation and the coolest hand-drawn diagram ever!


♾️ Render always​

Do you want to always render the changelog even if there are no changes? Boom, now you can now use the render_always option:

[changelog]
render_always = true

📤 Output from configuration​

This is pretty self-explanatory:

[changelog]
output = "CHANGELOG.md"

This option does not take precedence over command-line arguments which means you can override it with the --output option.


📦 Improve Typescript API​

We added the missing options and documented all options with tsdoc comments.

Also, we improved the skipCommit option to accept an array of values.

info

See the implementation for more information.


✂️ Trim commit messages​

We now remove the trailing newline for commits, which means you can use $ anchor in your regular expressions:

[git]
commit_preprocessors = [
# remove the issue number at the end of the commit message (e.g. #123)
{ pattern = ' #\d+$', replace = ""}
]

🌟 Better example templates​

The example templates are now more intuitive and conventionally correct. We removed the non-beginner-friendly options and changed the defaults to be easier to start with. Weheee!


🧰 Other​

  • (template) [breaking/core] Add name parameter to the constructor - (e577113)
  • (bump) Suppress template warning when --bumped-version is used (#855) - (8bebbf9)
  • (changelog) Do not change the tag date if tag already exists (#861) - (fbb643b)
  • (changelog) Correctly set the tag message for the latest release (#854) - (e41e8dd)
  • (changelog) Don't change the context when provided via --from-context (#820) - (ff72406)

Contributions 👥​

  • @nejcgalof made their first contribution in #853
  • @pplmx made their first contribution in #824

Any contribution is highly appreciated! See the contribution guidelines for getting started.

Feel free to submit issues and join our Discord / Matrix for discussion!

Follow git-cliff on Twitter & Mastodon to not miss any news!

Support 🌟​

If you liked git-cliff and/or my other projects on GitHub, consider donating to support my open source endeavors.

Have a fantastic day! ⛰️