File: README.md
[Documentation](https://git-cliff.org/docs) | [Website](https://git-cliff.org)
git-cliff can generate changelog files from the Git history by utilizing conventional commits as well as regex-powered custom parsers. The changelog template can be customized with a configuration file to match the desired format.
Documentation
Learn how to use git-cliff from the official documentation.
You can also check out the blog posts written by the community:
- An introduction to git-cliff for release management: Learn how to automate your software releases
- Git-cliff and monorepos: An introduction to the monorepo capabilities of git-cliff
- git-cliff: The Smart Way to Handle Changelogs
In The Media
- Turning Git commits into changelog with git-cliff - RustLab 2023 (Talk)
- An Interview with Orhun of git-cliff - Console #141 (Newsletter)
- KaiCode Open Source Festival 2024 (Second place winner)
Editor Support
- git-cliff.el - Generate, update and release changelog in Emacs
Similar/Related Projects
- git-journal - The Git Commit Message and Changelog Generation Framework
- clog-cli - Generate beautiful changelogs from your Git commit history
- relnotes - A tool to automatically generate release notes for your project.
- cocogitto - A set of CLI tools for the conventional commit and semver specifications.
- cliff-jumper - A NodeJS CLI tool that combines git-cliff and
conventional-recommended-bump
to semantically bump a NodeJS package and generate a git-cliff powered changelog. - release-plz - Release Rust packages from CI.
- git-changelog-command-line - Generate changelog and determine next version with conventional commits.
- git-changelog: Automatic Changelog generator using Jinja2 templates.
Contributors
Thanks goes to these wonderful people ✨
Made with contrib.rocks.
Socials
License
Licensed under either of Apache License Version 2.0 or The MIT License at your option.
Copyright
Copyright © 2021-2025, git-cliff contributors
File: website/docs/development/contributing.md
Contributing
See the contributing guide on GitHub.
File: website/docs/development/profiling.md
sidebar_position: 1
Performance Profiling
git-cliff can be built with performance profiling instrumentation, which helps with finding bottlenecks.
The profiler can be enabled via the profiler feature and the bench build profile.
cargo build --profile=bench --features=profilerTo create a flame graph SVG:
cargo run --profile=bench --features=profilere.g.
File: website/docs/configuration/bump.md
`bump`
This section contains the bump version related configuration options.
[bump]
features_always_bump_minor = true
breaking_always_bump_major = true
initial_tag = "0.1.0"features_always_bump_minor
Configures automatic minor version increments for feature changes.
When true, a feature will always trigger a minor version update.
When false, a feature will trigger:
- A patch version update if the major version is 0.
- A minor version update otherwise.
breaking_always_bump_major
Configures 0 -> 1 major version increments for breaking changes.
When true, a breaking change commit will always trigger a major version update
(including the transition from version 0 to 1)
When false, a breaking change commit will trigger:
- A minor version update if the major version is 0.
- A major version update otherwise.
initial_tag
Configures the initial version of the project.
When set, the version will be set to this value if no tags are found.
custom_major_increment_regex & custom_minor_increment_regex
Configures additional commit types that should increment the major or minor accordingly.
They should be used rarely, only in the case you have a special case for incrementing versions.
Expects a valid regex pattern.
For example:
[bump]
features_always_bump_minor = true
breaking_always_bump_major = true
custom_major_increment_regex = "major"
custom_minor_increment_regex = "minor|more"with this history:
5189568 (HEAD -> main) major: 1
0b17b48 (tag: 0.1.0) initial commitwill result in:
git-cliff --bumped-version
1.0.0or, with history:
47206d0 (HEAD -> main) more: 1
0b17b48 (tag: 0.1.0) initial commitwill result in:
git-cliff --bumped-version
0.2.0no_increment_regex
Configures commit types that should not increment the version.
This is useful when you want conventional commit types such as chore, ci
or docs to be ignored for version bumping.
Expects a valid regex pattern.
For example:
[bump]
no_increment_regex = "chore|ci|docs"with this history:
5189568 (HEAD -> main) chore: update CI
0b17b48 (tag: 0.1.0) initial commitwill result in:
git-cliff --bumped-version
0.1.0bump_type
When set, it forces to always bump in major, minor or patch.
e.g.
[bump]
bump_type = "minor"File: website/docs/configuration/git.md
`git`
This section contains the parsing and git related configuration options.
[git]
conventional_commits = true
filter_unconventional = true
require_conventional = false
split_commits = 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"},
]
protect_breaking_commits = false
filter_commits = false
fail_on_unmatched_commit = false
tag_pattern = "v[0-9].*"
skip_tags = "v0.1.0-beta.1"
ignore_tags = ""
topo_order = false
topo_order_commits = true
sort_commits = "oldest"
link_parsers = [
{ pattern = "#(\\d+)", href = "https://github.com/orhun/git-cliff/issues/$1"},
{ pattern = "RFC(\\d+)", text = "ietf-rfc$1", href = "https://datatracker.ietf.org/doc/html/rfc$1"},
]
processing_order = [
"commit_preprocessors",
"split_commits",
"conventional_commits",
"commit_parsers",
"link_parsers",
]
limit_commits = 42
limit_tags = 3
recurse_submodules = false
include_paths = ["src/", "doc/**/*.md"]
exclude_paths = ["unrelated/"]conventional_commits
If set to true, commits are parsed according to the Conventional Commits specifications.
The Conventional Commits specification is a lightweight convention on top of commit messages. It provides an easy set of rules for creating an explicit commit history; which makes it easier to write automated tools on top of. This convention dovetails with SemVer, by describing the features, fixes, and breaking changes made in commit messages.
The commit message should be structured as follows:
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]e.g. feat(parser): add ability to parse arrays
filter_unconventional
If set to true, commits that are not conventional are excluded. This option can be used to generate changelogs with conventional and unconventional commits mixed together. For example:
conventional_commits = true
filter_unconventional = false
commit_parsers = [
{ message = ".*", group = "Other", default_scope = "other"},
]With the configuration above, conventional commits are parsed as usual and unconventional commits will be also included in the changelog as "Other".
To completely exclude unconventional commits from the changelog:
# default behaviour
conventional_commits = true
filter_unconventional = trueTo include any type of commit in the changelog without parsing:
conventional_commits = false
filter_unconventional = falserequire_conventional
If set to true, all commits included in the changelog must be conventional. If any unconventional commits are found, an error will be logged and changelog generation fails.
conventional_commits = true
require_conventional = false
commit_parsers = [
{ message = ".*", group = "Other", default_scope = "other"},
{ message = "^Merging", skip = true }
]If set to true, this option takes precedence over filter_unconventional.
Checking takes place after commit_parsers. Thus commits can be skipped by matching parsers.
split_commits
This flag violates "conventional commits". It should remain off by default if conventional commits is to be respected.
If set to true, each line of a commit is processed individually, as if it were its own commit message. This may cause
a commit to appear multiple times in a changelog, once for each match.
conventional_commits = true
filter_unconventional = true
split_commits = true
commit_parsers = [
{ message = "^feat", group = "Features"},
]With the configuration above, lines are parsed as conventional commits and unconventional lines are omitted.
If filter_unconventional = false, every line will be processed as an unconventional commit, resulting in each line of
a commit being treated as a changelog entry.
processing_order
Defines a custom commit processing pipeline.
If this field is omitted, git-cliff uses the legacy processing flow for backwards compatibility.
Supported step names:
The default processing order is:
[git]
processing_order = [
"commit_preprocessors",
"split_commits",
"conventional_commits",
"commit_parsers",
"link_parsers",
]:::info
This is useful when you want e.g. split_commits to happen before parser-based filtering, so each split line is parsed independently.
:::
commit_preprocessors
An array of commit preprocessors for manipulating the commit messages before parsing/grouping them. These regex-based preprocessors can be used for removing or selecting certain parts of the commit message/body to be used in the following processes.
:::note
The replace or replace_command will take into account of the entire log of commit messages where the specified pattern is matched.
:::
Examples:
{ pattern = "foo", replace = "bar"}- Replace text.
{ pattern = 'Merged PR #[0-9]: (.*)', replace = "$1"}- Remove prefix.
{ pattern = " +", replace = " "}- Replace multiple spaces with a single space.
{ pattern = "\\(#([0-9]+)\\)", replace = "([#${1}](https://github.com/orhun/git-cliff/issues/${1}))"}- Replace the issue number with the link.
{ pattern = "https://github.com/[^ ]/issues/([0-9]+)", replace = "[Issue #${1}]"}- Replace the issue link with the number.
{ pattern = "Merge pull request #([0-9]+) from [^ ]+", replace = "PR # [${1}](https://github.com/orhun/git-cliff/pull/${1}):"}- Hyperlink PR references from merge commits.
{ pattern = "https://github.com/orhun/git-cliff/commit/([a-f0-9]{7})[a-f0-9]*", replace = "commit # [${1}](${0})"}- Hyperlink commit links, with short commit hash as description.
{ pattern = "([ \\n])(([a-f0-9]{7})[a-f0-9]*)", replace = "${1}commit # [${3}](https://github.com/orhun/git-cliff/commit/${2})"}- Hyperlink bare commit hashes like "abcd1234" in commit logs, with short commit hash as description.
Custom OS commands can also be used for modifying the commit messages:
{ pattern = "foo", replace_command = "pandoc -t commonmark"}
The above is equivalent to:
echo "<matched_part_of_the_changelog>" | pandoc -t commonmark
This is useful when you want to filter/encode messages using external commands. In the example above, pandoc is used to convert each commit message that matches the given pattern to the CommonMark format.
A more fun example would be reversing each commit message:
{ pattern = '.*', replace_command = 'rev | xargs echo "reversed: $@"' }
$COMMIT_SHA environment variable is set during execution of the command so you can do fancier things like reading the commit itself:
{ pattern = '.*', replace_command = 'git show -s --format=%B $COMMIT_SHA' }
commit_parsers
An array of commit parsers for determining the commit groups by using regex. The entire commit messages are affected wherever the regex is matched.
Examples:
{ message = "^feat", group = "Features" }- Group the commit as "Features" if the commit message (description) starts with "feat".
{ body = ".*security", group = "Security" }- Group the commit as "Security" if the commit body contains "security".
{ footer = "^changelog: ?ignore", skip = true }- Skip processing the commit if the commit footer contains "changelog: ignore".
{ message = '^fix\((.*)\)', group = 'Fix (${1})' }- Use the matched scope value from the commit message in the group name.
{ message = ".*deprecated", body = ".*deprecated", group = "Deprecation" }- Group the commit as "Deprecation" if the commit body and message contains "deprecated".
{ message = "^revert", skip = true }- Skip processing the commit if the commit message (description) starts with "revert".
{ message = "^doc", group = "Documentation", default_scope = "other" },- If the commit starts with "doc", group the commit as "Documentation" and set the default scope to "other". (e.g.
docs: xyzwill be processed asdocs(other): xyz)
- If the commit starts with "doc", group the commit as "Documentation" and set the default scope to "other". (e.g.
{ message = "(www)", scope = "Application" }- If the commit contains "(www)", override the scope with "Application". Scoping order is: scope specification, conventional commit's scope and default scope.
{ sha = "f6f2472bdf0bbb5f9fcaf2d72c1fa9f98f772bb2", skip = true }- Skip a specific commit by using its SHA1.
{ sha = "f6f2472bdf0bbb5f9fcaf2d72c1fa9f98f772bb2", group = "Stuff" }- Set the group of the commit by using its SHA1.
{ field = "author.name", pattern = "John Doe", group = "John's stuff" }- If the author's name attribute of the commit matches the pattern "John Doe" (as a regex), override the scope with "John's stuff".
- All values that are part of the commit context can be used. Nested fields can be accessed via the dot notation. Some commonly used ones are:
idmessageauthor.nameauthor.emailcommitter.emailcommitter.name
bodyis a special field which contains the body of a conventional commit, if applicable.- Be aware that all fields are converted to JSON strings before they are parsed by the given regex, especially when dealing with arrays.
protect_breaking_commits
If set to true, any breaking changes will be protected against being skipped
due to any commit parser.
filter_commits
If set to true, commits that are not matched by commit_parsers are filtered out.
fail_on_unmatched_commit
If set to true, git-cliff will fail (return a non-zero exit code) when any commit included in the changelog is not matched by any of the configured commit_parsers.
This option is useful to enforce that all commits are classified and prevents silently omitting unknown commit types from release notes.
:::note
Commits that are explicitly skipped by a parser (for example { message = "^revert", skip = true }) are not considered unmatched.
:::
tag_pattern
A regular expression for matching the git tags.
This value can be also overridden with using the --tag-pattern argument.
skip_tags
A regex for skip processing the matched tags.
This value can be also overridden with using the --skip-tags argument.
ignore_tags
A regex for ignore processing the matched tags.
While skip_tags drop commits from the changelog, ignore_tags include ignored commits into the next tag.
:::note
Note that if a commit has multiple tags, any matched tag will result in all associated tags being ignored, including those not explicitly matched by the regex. This is because git-cliff processes tags at the commit level rather than individually.
For more details, you can view the discussion here.
:::
This value can be also overridden with using the --ignore-tags argument.
count_tags
A regex for counting in the matched tags in the final result.
:::info
count_tags work like an inverted version of ignore_tags, that include all the commits but only count the specific tags.
:::
This value can be also overridden with using the --count-tags argument.
limit_tags
limit_tags is an optional integer number that limits the number of tags used for generating the changelog.
When no explicit commit range or --latest, --current, or --unreleased flag is provided, git-cliff uses the latest matched tags as a range window.
Setting this value to 0 is equivalent to not setting a limit.
This value can be also overridden with using the --limit-tags argument.
topo_order
If set to true, tags are processed in topological order instead of chronological.
This can also be achieved by using the --topo-order command line flag.
topo_order_commits
If set to true, commits are processed in topological order instead of chronological.
# if false, sorting commit is equivalent to git log
# if true (default), sorting commit is equivalent to git log --topo-order
topo_order_commits = falsesort_commits
Sort the commits inside sections by specified order.
Possible values:
oldestnewest
This can also be achieved by specifying the --sort command line argument.
The default value is oldest.
link_parsers
An array of link parsers for extracting external references, and turning them into URLs, using regex.
Examples:
{ pattern = "#(\\d+)", href = "https://github.com/orhun/git-cliff/issues/$1"}- Extract all GitHub issues and PRs and generate URLs linking to them. The link text will be the matching pattern.
{ pattern = "RFC(\\d+)", text = "ietf-rfc$1", href = "https://datatracker.ietf.org/doc/html/rfc$1"},- Extract mentions of IETF RFCs and generate URLs linking to them. It also rewrites the text as "ietf-rfc...".
These extracted links can be used in the template with commit.links variable.
limit_commits
limit_commits is an optional positive integer number that limits the number of included commits in the generated changelog.
limit_commits is not part of the default configuration.
recurse_submodules
recurse_submodules is an optional boolean value that indicates whether git-cliff should read and process commits of submodules.
This only considers submodules at the toplevel (depth 1). These commits can then be accessed by the variable submodule_commits during templating.
include_paths
include_paths is an optional array of glob patterns. Only commits that modify files matching these patterns will be included in the generated changelog.
When this value is set, the current working directory will not be included.
exclude_paths
exclude_paths is an optional array of glob patterns. Commits that only modify files matching these patterns will be excluded from the changelog.
This setting takes priority over include_paths.
- If a commit touches both included and excluded paths, it will be included.
- If a commit only modifies files that match both
include_pathsandexclude_paths, it will be excluded.
File: website/docs/configuration/index.md
sidebar_position: 4
Configuration
git-cliff configuration file supports TOML (preferred) and YAML formats.
File Path
When the --config option is not given, git-cliff automatically discovers the configuration file, first in the project directory and then in the global user directory. If no configuration file is found, git-cliff will use the default configuration values. See cliff.toml for the default configuration values.
Discovery starts from the directory given by --workdir when that option is used, and from the current directory otherwise.
:::tip
The configuration schema is published on SchemaStore.
:::
It looks for the following project configuration files in this order:
cliff.toml.cliff.toml.config/cliff.toml
If no configuration file is found in the current directory, it will search the parent directories.
Global Configuration
The global configuration file is located at:
<CONFIG_DIR>/git-cliff/cliff.toml<CONFIG_DIR> is the config_dir() returned by etcetera's default base strategy and depends on the platform:
- Linux:
$XDG_CONFIG_HOME, or~/.config - macOS:
$XDG_CONFIG_HOME, or~/.config - Windows:
%APPDATA%(typically~\AppData\Roaming)
On macOS, the legacy ~/Library/Application Support/git-cliff/cliff.toml path is also supported for backwards compatibility.
Environment Configuration Overrides
It's possible to use environment variables to override configuration elements. If an environment variable matches a configuration element, the variable's value will be used instead of the element's.
Format:
[PREFIX]__[CONFIG SECTION]__[FIELD NAME]Examples
To override the footer element:
export GIT_CLIFF__CHANGELOG__FOOTER=""To override the ignore_tags element:
export GIT_CLIFF__GIT__IGNORE_TAGS="v[0-9]+.[0-9]+.[0-9]+-rc[0-9]+"File: website/docs/configuration/remote.md
`remote`
This section contains the Git remote related configuration options.
You can configure a remote for GitHub, GitLab, Gitea/Forgejo or Bitbucket as follows:
[remote.github]
owner = "orhun"
repo = "git-cliff"
token = ""Change this to remote.gitlab, remote.gitea or remote.bitbucket accordingly to your project.
:::tip
- See the GitHub integration.
- See the GitLab integration.
- See the Gitea integration.
- See the Bitbucket integration.
:::
owner
Sets the owner (username) of the Git remote.
repo
Sets the name of the repository.
If you are using GitHub, you can use the --github-repo argument or GITHUB_REPO environment variable.
e.g.
git cliff --github-repo orhun/git-cliffSame applies for GitLab/Bitbucket with --gitlab-repo/--gitea-repo/--bitbucket-repo and GITLAB_REPO/GITEA_REPO/BITBUCKET_REPO environment variables.
token
Sets the access token for the remote.
If you are using GitHub, then you can also pass this value via --github-token argument or GITHUB_TOKEN environment variable as follows:
git cliff --github-token <TOKEN>Same applies for GitLab/Bitbucket with --gitlab-token/--gitea-token/--bitbucket-token and GITLAB_TOKEN/GITEA_TOKEN/BITBUCKET_TOKEN environment variables.
api_url
Sets the API URL for a particular remote.
http_timeout
Sets the HTTP request timeout for remote metadata fetches.
This value is a duration, for example:
[remote.github]
http_timeout = "60s"You can also override it from the CLI with --http-timeout <SECS> or via the GIT_CLIFF_HTTP_TIMEOUT environment variable.
native_tls
When set to true, the TLS certificates are loaded from the platform's native certificate store.
:::info
By default, git-cliff loads certificates from the bundled webpki-roots crate which is a reliable set of trust roots from Mozilla.
However, in some cases, you may want to use the platform's native certificate store, especially if you're relying on a corporate trust root (e.g., for a mandatory proxy) that's included in your system's certificate store.
:::
offline
When the --offline argument, GIT_CLIFF_OFFLINE environment variable, or configuration parameter is set, git-cliff ensures that no external calls or requests are made, despite a remote being configured. This can be useful when running --bumped-version or in a limited environment.
Here is a complete example for a project hosted on GitLab:
[remote]
offline = false
[remote.gitlab]
owner = "archlinux"
repo = "arch-repro-status"
api_url = "https://gitlab.archlinux.org/api/v4"
token = "deadbeef"
http_timeout = "60s"
native_tls = falseFile: website/docs/github-actions/git-cliff-action.md
git-cliff-action
It is possible to generate changelogs using GitHub Actions via git-cliff-action.
- name: Check out repository
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Generate a changelog
uses: orhun/git-cliff-action@v4
with:
config: cliff.toml
args: --verbose
env:
OUTPUT: CHANGELOG.md
GITHUB_REPO: ${{ github.repository }}See the repository for other examples.
Also, see the continuous deployment workflow of this project which sets the release notes for GitHub releases using this action.
File: website/docs/github-actions/setup-git-cliff.md
setup-git-cliff
There is also another GitHub Action which is setup-git-cliff.
While git-cliff-action uses the Docker image generated by docker.yml, setup-git-cliff installs the binary executable in the release artifacts:
- name: Check out repository
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Set up git-cliff
uses: kenji-miyake/setup-git-cliff@v1
- name: Run git-cliff
run: git cliffSee a practical example here.
File: website/docs/github-actions/taiki-e-install-action.md
taiki-e/install-action
taiki-e/install-action enables a manual workflow
where git-cliff is automatically installed into your GitHub Actions environment from pre-built releases
and you can invoke it in subsequent shell script steps.
For example:
- name: Check out repository
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Install git-cliff
uses: taiki-e/install-action@git-cliff
- name: Generate changelog
run: git-cliff