agentsclimarketplace

Git cliff

Skill kpatryk/skills/skills/git-cliff

AI skills

Install
npx -y skills add kpatryk/skills --skill git-cliff

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Expert guide for git-cliff, a highly customizable changelog generator from git history. Invoke this skill whenever the user wants to generate, update, or customize a CHANGELOG.md file; auto-bump semantic versions; configure cliff.toml; write Tera templates for changelogs; work with conventional commits for changelog purposes; set up git-cliff in CI/CD pipelines; filter commits by path for monorepos; integrate GitHub/GitLab remote metadata into changelogs; debug changelog output; or run any git-cliff CLI command. Use even when the user just says "generate changelog", "update my CHANGELOG", "prep release notes", or "bump my version" — any changelog or release-notes workflow likely benefits from this skill.

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

13.6 KB, as published. Nobody here has run it

git-cliff

git-cliff generates beautiful, customizable changelogs from git history using conventional commits and regex-powered custom parsers. The changelog body is a Tera template (similar to Jinja2/Django templates).

Core Concepts

  • Config file: cliff.toml in the project root (or ~/.config/git-cliff/cliff.toml globally)
  • Template engine: Tera — {{ variable }}, {% for %}, {% if %}, filters like | upper_first
  • Conventional commits: <type>[scope]: <description> — types include feat, fix, docs, refactor, perf, test, chore, style, build, ci
  • Breaking changes: feat!: / fix!: suffix or BREAKING CHANGE: footer → SemVer major bump
  • feat: → minor bump · fix: → patch bump

Quickstart

git-cliff --init          # scaffold cliff.toml in the current directory
git-cliff -o CHANGELOG.md # generate full changelog from all history

CLI Reference

Boolean flags

FlagDescription
-u, --unreleasedOnly commits not yet associated with a tag
-l, --latestCommits from the latest tag to HEAD
--currentCommits belonging to the currently checked-out tag
--topo-orderSort tags topologically instead of chronologically
--bumped-versionPrint the auto-bumped version string only (no changelog)
-x, --contextPrint the template context as JSON (great for debugging)
--no-execDisable external command execution in pre/postprocessors
--use-branch-tagsOnly include tags reachable from the current branch
--offlineDisable network access (remote integrations)

Options

OptionShortDescription
--config <PATH>-cConfig file path (default: cliff.toml; env: GIT_CLIFF_CONFIG)
--tag <TAG>-tLabel unreleased commits as this version
--output [<PATH>]-oWrite to file (omit path → writes to CHANGELOG.md)
--prepend <PATH>-pPrepend new entries to an existing changelog file
--bumpAuto-bump version: auto (default), major, minor, or patch
--body <TEMPLATE>-bOverride the body template inline
--strip <PART>-sStrip header, footer, or all from output
--sort <SORT>Commit sort inside sections: oldest (default) or newest
--include-path <PATTERN>Only include commits that touch these paths (glob)
--exclude-path <PATTERN>Exclude commits touching these paths (glob)
--tag-pattern <PATTERN>Regex for matching git tags
--skip-tags <PATTERN>Regex — skip these tags entirely
--ignore-tags <PATTERN>Ignore these tags (their commits roll into the next release)
--with-commit <MSG>Inject a synthetic commit message
--skip-commit <SHA>Skip a specific commit by SHA
--workdir <PATH>-wSet the working directory
--repository <PATH>-rSet the git repository path
[RANGE]Git commit range, e.g. v1.0.0..HEAD

Remote Integration

git-cliff --github-token $GITHUB_TOKEN --github-repo owner/repo
git-cliff --gitlab-token $GITLAB_TOKEN --gitlab-repo owner/repo
# Also: --gitea-*, --bitbucket-*, --azure-devops-*

cliff.toml Schema

[changelog]
header = "# Changelog\n\nAll notable changes to this project will be documented in this file.\n"
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.scope %}*({{ commit.scope }})* {% endif %}\
  {% if commit.breaking %}[**breaking**] {% endif %}\
  {{ commit.message | upper_first }}
{% endfor %}
{% endfor %}
"""
footer = "<!-- generated by git-cliff -->"
trim = true          # strip leading/trailing whitespace from rendered body
# render_always = false   # render body even when there are no releases
# output = "CHANGELOG.md" # set default output path in config

postprocessors = [
  # Regex replace across the final output string:
  # { pattern = "\\(#([0-9]+)\\)", replace = "([#${1}](https://github.com/owner/repo/issues/${1}))" }
]

[git]
conventional_commits = true    # parse <type>[scope]: <desc> format
filter_unconventional = true   # exclude non-conventional commits
# require_conventional = false # fail if any included commit is non-conventional
# split_commits = false        # treat each commit body line as its own commit

commit_preprocessors = [
  # Mutate commit messages before parsing:
  # { pattern = " +", replace = " " }   # collapse multiple spaces
  # { pattern = "Merge pull request #([0-9]+) from [^ ]+", replace = "PR #${1}:" }
]

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|^ci|^build",  group = "Miscellaneous Tasks" },
  { message = "^revert",            skip = true },
  # { body = ".*security",          group = "Security" },
  # { footer = "^changelog: ?ignore", skip = true },
  # { sha = "abc1234",              skip = true },
]

protect_breaking_commits = false  # never skip breaking changes, even if a parser would
filter_commits = false            # if true, drop commits not matched by any parser
# fail_on_unmatched_commit = false

tag_pattern = "v[0-9].*"    # regex for recognizing version tags
# skip_tags = "v0.1.0-beta.1"
# ignore_tags = "-rc[0-9]+$"  # roll RC commits into the next full release

topo_order = false           # topological tag ordering
sort_commits = "oldest"      # oldest | newest

link_parsers = [
  # Extract issue links from commit messages:
  # { pattern = "#(\\d+)", href = "https://github.com/owner/repo/issues/$1" },
]

# limit_commits = 100
# include_paths = ["src/", "lib/**"]
# exclude_paths = ["vendor/"]

Tera Template Context

The body template receives one release object per tag. header and footer receive the full releases array.

Release fields

FieldTypeDescription
versionstringTag name, e.g. "v1.2.0" (null for unreleased)
messagestringAnnotated tag message
timestampintUnix timestamp of the release commit
previousobject{ version } of the prior release
commitsarrayCommit objects (see below)
commit_idstringSHA of the release commit
statisticsobjectcommit_count, commits_timespan, conventional_commit_count, links[], days_passed_since_last_release

Commit fields

FieldTypeDescription
idstringFull commit SHA
messagestringCommit description (after type/scope parsing)
groupstringSet by commit_parsers
scopestringConventional commit scope
breakingbooltrue if breaking change
breaking_descriptionstringExplanation from BREAKING CHANGE: footer
bodystringFull commit body text
footersarray{ token, separator, value, breaking }
conventionalboolWas parsed as conventional?
merge_commitboolIs a merge commit?
authorobject{ name, email, timestamp }
committerobject{ name, email, timestamp }
linksarray{ text, href } from link_parsers
remoteobject{ username, pr_title, pr_number, pr_labels, is_first_contributor }

Useful Tera patterns

{# Group by group label and list scoped commits #}
{% for group, commits in commits | group_by(attribute="group") %}
### {{ group | upper_first }}
{% for commit in commits | sort(attribute="message") %}
- {% if commit.scope %}*({{ commit.scope }})* {% endif %}{{ commit.message | upper_first }}
{% endfor %}
{% endfor %}

{# Highlight breaking changes separately #}
{% set breaking = commits | filter(attribute="breaking", value=true) %}
{% if breaking | length > 0 %}
### ⚠️ Breaking Changes
{% for commit in breaking %}
- {{ commit.breaking_description | default(value=commit.message) | upper_first }}
{% endfor %}
{% endif %}

{# Comparison links in footer using previous version #}
{% for release in releases %}
{% if release.previous.version %}
[{{ release.version }}]: https://github.com/owner/repo/compare/{{ release.previous.version }}..{{ release.version }}
{% endif %}
{% endfor %}

{# Trim version prefix for display #}
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}

Key Tera built-ins: upper_first, lower, upper, trim, trim_start_matches(pat=...), replace(from=..., to=...), indent(prefix=...), group_by(attribute=...), filter(attribute=..., value=...), sort(attribute=...), unique, length, date(format=...), default(value=...), join(sep=...)


Common Workflows

1. Initialize and generate full changelog

git-cliff --init           # creates cliff.toml
git-cliff -o CHANGELOG.md  # writes complete changelog

2. Preview unreleased changes

git-cliff --unreleased
git-cliff --unreleased --tag 2.0.0  # label what the next release will be

3. Prepend unreleased to existing changelog (typical release flow)

git-cliff --unreleased --tag v1.3.0 --prepend CHANGELOG.md
# Note: --prepend and -o with the same path are incompatible

4. Auto-bump + prepend (fully automated release)

VERSION=$(git-cliff --bumped-version)
git-cliff --unreleased --tag "$VERSION" --prepend CHANGELOG.md
git add CHANGELOG.md && git commit -m "chore(release): $VERSION"
git tag "$VERSION" && git push --follow-tags

5. Generate for a specific range

git-cliff v1.0.0..HEAD
git-cliff v1.0.0..v2.0.0
git-cliff HEAD~10..        # last 10 commits only

6. Latest release notes only

git-cliff --latest -o RELEASE_NOTES.md
git-cliff --latest --strip all   # body only, no header/footer

7. Debug your template

git-cliff --context                    # print full JSON context
git-cliff --context | jq '.[0].commits[] | {group, scope, message}'

8. Monorepo per-package changelogs

git-cliff --include-path "packages/my-lib/**" \
          --tag-pattern "my-lib-v[0-9].*" \
          --tag my-lib-v1.0.0 \
          -o packages/my-lib/CHANGELOG.md

9. GitHub integration (PR titles, authors, labels)

GITHUB_TOKEN=xxx git-cliff --github-repo owner/repo -o CHANGELOG.md

10. CI/CD (GitHub Actions example)

- name: Generate changelog
  run: |
    VERSION=$(git-cliff --bumped-version)
    git-cliff --unreleased --tag "$VERSION" --prepend CHANGELOG.md
  env:
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Environment Variables

Config field overrides use the pattern GIT_CLIFF__<SECTION>__<FIELD> (double underscore):

export GIT_CLIFF__CHANGELOG__FOOTER="<!-- generated by git-cliff -->"
export GIT_CLIFF__GIT__IGNORE_TAGS="v[0-9]+\.[0-9]+\.[0-9]+-rc[0-9]+"
export GIT_CLIFF_CONFIG=./custom-cliff.toml
export GIT_CLIFF_OUTPUT=CHANGELOG.md
export GITHUB_TOKEN=ghp_xxx  # for GitHub remote integration

Tips & Patterns

  • Debug first: Run git-cliff --context | jq to see exactly what data your template receives before writing the template.
  • protect_breaking_commits = true: Ensures breaking changes always appear even if a skip rule would otherwise hide them.
  • filter_commits = true: Drop any commit not matched by commit_parsers — great for noise-free changelogs.
  • Opt-out per commit: Add { footer = "^changelog: ?ignore", skip = true } to let authors mark individual commits as "don't include".
  • Monorepo: Use --include-path per package with per-package tag patterns. Version tags can be prefixed: my-pkg-v1.0.0.
  • PR labels as groups: With GitHub remote integration, match remote.pr_labels in commit_parsers to group by PR label categories.
  • split_commits = true: Treats each line of a commit body as a separate entry — useful when squash merges pack multiple changes into one commit message.
  • ignore_tags vs skip_tags: ignore_tags rolls the commits into the next release; skip_tags drops them entirely.
  • Postprocessors: Run regex replacements on the final rendered changelog string — useful for linkifying issue numbers globally.

Reference

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.