Skip to main content

Tips And Tricks

Changing the group orderโ€‹

Since the groups come out in alphabetical order, use HTML comments to force them into their desired positions:

[git]
commit_parsers = [
{ message = "^feat*", group = "<!-- 0 -->:rocket: New features" },
{ message = "^fix*", group = "<!-- 1 -->:bug: Bug fixes" },
{ message = "^perf*", group = "<!-- 2 -->:zap: Performance" },
{ message = "^chore*", group = "<!-- 3 -->:gear: Miscellaneous" },
]

This produces the following order:

  • ๐Ÿš€ New features
  • ๐Ÿ› Bug fixes
  • โšก Performance
  • โš™๏ธ Miscellaneous

Then strip the tags in the template with the series of filters:

### {{ group | striptags | trim | upper_first }}
info

If you are using the built-in commit_groups filter, you can also pass the commit_parsers_groups context field to keep the parser order without embedding ordering tags:

{% for entry in commits | commit_groups(groups=commit_parsers_groups) %}
### {{ entry.group | trim | upper_first }}
{% endfor %}

For example, given these commit_parsers and the custom commit_groups filter:

[git]
commit_parsers = [
{ message = "^feat", group = "New features" },
{ message = "^fix", group = "Bug fixes" },
{ message = "^perf", group = "Performance" },
]

The template above renders:

### New features

- feat: add parser-order docs

### Bug fixes

- fix: keep group order stable

### Performance

- perf: speed up changelog rendering

Discard duplicate commitsโ€‹

{% for commit in commits | unique(attribute="message") %}

Filter merge commitsโ€‹

{% for group, commits in commits | filter(attribute="merge_commit", value=false) | group_by(attribute="group") %}

Remove gitmojiโ€‹

[git]
commit_preprocessors = [
# Remove gitmoji, both actual UTF emoji and :emoji:
{ pattern = ' *(:\w+:|[\p{Emoji_Presentation}\p{Extended_Pictographic}](?:\u{FE0F})?\u{200D}?) *', replace = "" },
]

Skip commits with an empty bodyโ€‹

[git]
commit_parsers = [
{ body = "$^", skip = true },
]

Skip commits by GitHub PR labelโ€‹

{% if commit.remote.pr_labels is containing("skip-release-notes") %}
{% continue %}
{% endif %}

Use GitHub PR labels as groupsโ€‹

[git]
commit_parsers = [
{ field = "github.pr_labels", pattern = "breaking-change", group = "<!-- 0 --> ๐Ÿ—๏ธ Breaking changes" },
{ field = "github.pr_labels", pattern = "type/enhancement", group = "<!-- 1 --> ๐Ÿš€ Features" },
{ field = "github.pr_labels", pattern = "type/bug", group = "<!-- 2 --> ๐Ÿ› Fixes" },
{ field = "github.pr_labels", pattern = "type/update", group = "<!-- 3 --> ๐Ÿงช Dependencies" },
{ field = "github.pr_labels", pattern = "type/refactor", group = "<!-- 4 --> ๐Ÿญ Refactor" },
{ field = "github.pr_labels", pattern = "area/documentation", group = "<!-- 5 --> ๐Ÿ“ Documentation" },
{ field = "github.pr_labels", pattern = ".*", group = "<!-- 6 --> ๐ŸŒ€ Miscellaneous" },
]

Use GitLab CI variablesโ€‹

{{ get_env(name="CI_PROJECT_URL") }}/-/tags/{{ version }}

Convert markdown output to PDFโ€‹

pandoc --from=gfm --to=pdf -o CHANGELOG.pdf CHANGELOG.md

To support unicode characters, use xelatex as PDF engine and a font family which includes the needed unicode characters:

pandoc --from=gfm --to=pdf --pdf-engine=xelatex -o CHANGELOG.pdf CHANGELOG.md --variable mainfont="Segoe UI Emoji"

Handling remote Git service API rate limitsโ€‹

When retrieving information from a remote Git repository, you may encounter HTTP 403 errors due to rate limiting.

As a simple workaround, you can run git-cliff in offline mode to skip remote API calls:

git-cliff --offline
# or via environment variable
GIT_CLIFF_OFFLINE=true git-cliff
note

This will generate the changelog using only local Git commit information. Note that PR titles, labels, and other remote metadata will not be included in offline mode.

Parsing commits with multiple parsersโ€‹

Use continue = true to apply more than one commit_parser to a commit:

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