What's diff whatsdiff
CLI Tool

Changelog Command

Read release notes for updated packages in your terminal.

On this page 18

changelog reads release notes in your terminal, either for one package or for every package that changed in your project.

The changelog command output

bash
whatsdiff changelog [package] [version] [options]

Every updated package

Run it with no arguments and it aggregates release notes for every package that was updated or downgraded:

bash
whatsdiff changelog

It finds the changed packages the same way analyse does, comparing your working tree against the previous commit unless you pass --from and --to. This is the quickest way to review what a composer update or npm update actually brought in, without running the command once per package.

bash
whatsdiff changelog --from=v1.0.0 --to=v2.0.0
whatsdiff changelog --include=composer --format=markdown

A single package in your project

Name a package and whatsdiff finds it in your composer.lock or package-lock.json, works out the version change from your git history, and prints the release notes in between:

bash
whatsdiff changelog symfony/console

Point it at other revisions with --from and --to:

bash
whatsdiff changelog doctrine/orm --from=abc123 --to=def456
whatsdiff changelog guzzlehttp/guzzle --from=v1.0.0

Any package, anywhere

To read the notes for a package you have not installed, add --type so whatsdiff knows which registry to query. This works outside a project entirely, which is handy when you are still deciding whether to add a dependency:

bash
whatsdiff changelog react --type=npm
whatsdiff changelog symfony/mailer --type=composer

Pass a version or a range as the second argument:

bash
whatsdiff changelog laravel/framework 11.0.0
whatsdiff changelog symfony/console 6.0.0...6.4.0

Options

Option Description
--from Commit, branch, or tag to read the starting version from
--to Commit, branch, or tag to read the ending version from (defaults to HEAD)
--ignore-last Ignore uncommitted changes
-t, --type Registry to query directly: composer or npm
--include Only these package managers (comma-separated: composer, npmjs)
--exclude Everything but these package managers
-f, --format Output format: text (default), json, or markdown
-s, --summary Combine every release into a single list of changes
--include-prerelease Include beta, alpha, and RC versions, which are skipped by default
--no-cache Bypass the cache and fetch fresh data

--include and --exclude are mutually exclusive, and they only apply when aggregating. The positional version argument requires a package argument.

Output formats

Text

bash
whatsdiff changelog guzzlehttp/guzzle 7.8.1 --type=composer
code
Release Notes
--------------------------------------------------------------------------------

7.8.1 - Release 7.8.1
Date: 2023-12-03
URL: https://github.com/guzzle/guzzle/releases/tag/7.8.1

Changes:
  • Updated links in docs to their canonical versions
  • Replaced `call_user_func*` with native calls

--------------------------------------------------------------------------------

When aggregating, each package gets a {package} ({from} → {to}) header followed by an 80-character separator, with a blank line between packages:

code
guzzlehttp/psr7 (2.8.0 → 2.9.0)
================================================================================

2.9.0
Date: 2026-03-10

Changes:
  • Added nested array expansion support to `MultipartStream`
  • Added `@return static` to `MessageTrait` methods
  • Updated MIME type mappings

--------------------------------------------------------------------------------

2.8.1
Date: 2026-03-10

Fixes:
  • Encode `+` signs in `Uri::withQueryValue()` and `Uri::withQueryValues()` to prevent them being interpreted as spaces


saloonphp/saloon (3.14.2 → 4.0.0)
================================================================================
… (release entries per version)

JSON

bash
whatsdiff changelog guzzlehttp/guzzle 7.8.1 --type=composer --format=json
json
{
    "total_releases": 1,
    "releases": [
        {
            "tag_name": "7.8.1",
            "title": "Release 7.8.1",
            "date": "2023-12-03T20:36:10Z",
            "url": "https://github.com/guzzle/guzzle/releases/tag/7.8.1",
            "body": "### Changed\r\n\r\n- Updated links in docs to their canonical versions\r\n- Replaced `call_user_func*` with native calls\r\n",
            "changes": [
                "Updated links in docs to their canonical versions",
                "Replaced `call_user_func*` with native calls"
            ],
            "fixes": [],
            "breaking_changes": []
        }
    ]
}

Aggregating wraps the same release shape in a packages array. Each entry carries the package name, its manager type, the resolved from_version and to_version, and first_tag and last_tag markers. With --summary, each entry also gets an aggregated summary object.

json
{
    "total_packages": 2,
    "packages": [
        {
            "package": "guzzlehttp/psr7",
            "type": "composer",
            "from_version": "2.8.0",
            "to_version": "2.9.0",
            "total_releases": 2,
            "releases": [
                {
                    "tag_name": "2.9.0",
                    "title": "2.9.0",
                    "date": "2026-03-10T09:03:43Z",
                    "url": null,
                    "body": "### Added\n- Added nested array expansion support to `MultipartStream`\n…",
                    "changes": ["Added nested array expansion support to `MultipartStream`", "…"],
                    "fixes": [],
                    "breaking_changes": [],
                    "deprecated": [],
                    "removed": [],
                    "security": []
                }
            ],
            "first_tag": "2.9.0",
            "last_tag": "2.8.1"
        }
    ]
}

Markdown

bash
whatsdiff changelog guzzlehttp/guzzle 7.8.1 --type=composer --format=markdown
markdown
# Release Notes

## 7.8.1 - Release 7.8.1

**Date:** 2023-12-03
**URL:** https://github.com/guzzle/guzzle/releases/tag/7.8.1

### Changes
- Updated links in docs to their canonical versions
- Replaced `call_user_func*` with native calls

When aggregating, each package becomes a top-level # heading and the release entries below it reuse the layout above.

No updated packages

All three formats return an empty result rather than failing:

Format Output
Text No updated packages found.
Markdown _No updated packages found._
JSON {"total_packages": 0, "packages": []}

The summary view

--summary folds every release in the range into one list of changes, which makes breaking changes much easier to spot when you are debugging after an upgrade:

bash
whatsdiff changelog guzzlehttp/guzzle 7.7.0...7.8.1 --type=composer --summary
code
Release Notes Summary
--------------------------------------------------------------------------------

Total Releases: 3

Changes:
  • Updated links in docs to their canonical versions
  • Replaced `call_user_func*` with native calls
  • Added support for PHP 8.3
  • Improved error handling for network timeouts
  • Fixed issue with header parsing

--------------------------------------------------------------------------------

Use cases

Writing release notes for a pull request

One command produces the full review surface for a dependency bump, ready to paste into the description:

bash
whatsdiff changelog --from=origin/main --to=HEAD --format=markdown > pr-notes.md

Reviewing a package before you upgrade

Read what is waiting for you before running composer update:

bash
whatsdiff changelog laravel/framework
whatsdiff changelog symfony/console 6.0.0...7.0.0

Tracking down a breaking change

When something broke after an update, --summary collapses every release in the range into one list, which is faster to scan than release-by-release output:

bash
whatsdiff changelog symfony/http-kernel --summary

Reviewing someone else's dependency bump

On a branch that touches the lock files, aggregate mode covers every package at once:

bash
git checkout feature/update-deps
whatsdiff changelog

Auditing what changed between two releases

bash
whatsdiff changelog symfony/security-core --from=v2.0.0 --to=v3.0.0

Feeding another tool

JSON output drops straight into a deployment script or a dashboard:

bash
whatsdiff changelog --format=json > deployment-changes.json
  • analyse shows the version changes without the release notes
  • tui browses both together in an interactive interface