Changelog Command
View release notes and changelogs for updated packages directly in your terminal — for a single package, or aggregated across every package that changed in your project.

Usage
whatsdiff changelog [package] [version] [options]
Omit the package argument to aggregate changelogs for every package that was updated (or downgraded) between two refs.
Arguments
[package]- Optional. Package name (e.g.,symfony/consolefor Composer,reactfor npm). When omitted, the command shows changelogs for every updated package in your project.[version]- Optional version or version range (e.g.,5.1.0or5.0.0...5.1.0). Only valid when a package is specified.
Options
You can filter by changes made in your project:
--from=FROM- Git commit, branch, or tag to get the starting version from--to=TO- Git commit, branch, or tag to get the ending version from (defaults to HEAD)--ignore-last- Ignore last uncommitted changes
Or if you want a changelog for a specific package even outside of your project:
-t, --type=TYPE- Specify package manager type (composerornpm)
Filtering options (aggregate mode only):
--include=INCLUDE- Include only specific package manager types (comma-separated:composer,npmjs)--exclude=EXCLUDE- Exclude specific package manager types (comma-separated:composer,npmjs)
Other options:
-f, --format=FORMAT- Output format:text(default),json, ormarkdown-s, --summary- Show summarized changelog (combines all releases into one view)--no-cache- Disable caching for this request--include-prerelease- Include pre-release versions (beta, alpha, RC, etc.)
Option Conflicts
--includeand--excludeare mutually exclusive- The positional
versionargument requires apackageargument
Three Modes of Operation
The changelog command works in three distinct modes depending on how you invoke it:
Aggregate Mode (All Updated Packages)
Run the command without a package argument to aggregate release notes for every package that was updated or downgraded between two refs:
whatsdiff changelog
The command:
- Uses the same comparison logic as
analyseto find every changed package between--fromand--to(defaults to comparing your working tree against the previous commit) - Resolves release notes for each updated/downgraded package and prints them grouped by package
- Can be scoped to one ecosystem with
--include=composeror--include=npmjs - Supports the same
--formatoptions (text, JSON, markdown) and the--summaryflag
This mode is the easiest way to review everything a composer update or npm update brought in — without having to invoke changelog once per package.
Single Package, Inside a Project (Git-Based)
When you run the command inside a git repository with lock files:
whatsdiff changelog symfony/console
The command:
- Detects the package in your
composer.lockorpackage-lock.json - Automatically determines version changes from your git history
- Compares the current version with the previous version in your commits
- Perfect for reviewing changes after
composer updateornpm update
Single Package, Outside a Project (Direct Query)
When you want to check any package's changelog without having it in your project:
whatsdiff changelog symfony/console --type=composer
whatsdiff changelog react --type=npm
The command:
- Queries the package registry directly (Packagist or npm)
- Requires the
--typeflag to specify the package manager - You can specify exact versions or ranges
- Useful for researching packages before adding them to your project
Output Formats
The changelog command supports three output formats that can be selected with the --format option.
Text Format (Default)
Human-readable format with clear sections for each release:
whatsdiff changelog guzzlehttp/guzzle 7.8.1 --type=composer
Output:
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
--------------------------------------------------------------------------------
JSON Format
Structured data format perfect for automation and CI/CD pipelines:
whatsdiff changelog guzzlehttp/guzzle 7.8.1 --type=composer --format=json
Output:
{
"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": []
}
]
}
Markdown Format
Formatted markdown ready to copy into documentation:
whatsdiff changelog guzzlehttp/guzzle 7.8.1 --type=composer --format=markdown
Output:
# 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
Summary View
Use the --summary flag to aggregate changes across multiple releases:
whatsdiff changelog guzzlehttp/guzzle 7.7.0...7.8.1 --type=composer --summary
Output:
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
--------------------------------------------------------------------------------
This is useful for getting a quick overview of all changes without the detail of individual releases.
Aggregate Mode Output
When no package argument is given, the command emits one section per updated package using the same three formats.
Text:
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)
Per-package headers use the {package} ({from} → {to}) format followed by an 80-character separator, with a blank line between packages.
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"
}
]
}
Each entry in packages[] carries the package name, manager type, resolved from_version / to_version, the full releases array (same shape as single-package mode), and first_tag / last_tag markers. When --summary is passed, each entry also includes an aggregated summary object.
Markdown:
# guzzlehttp/psr7 (2.8.0 → 2.9.0)
## 2.9.0
**Date:** 2026-03-10
### Added
- Added nested array expansion support to `MultipartStream`
- Added `@return static` to `MessageTrait` methods
---
## 2.8.1
**Date:** 2026-03-10
### Fixed
- Encode `+` signs in `Uri::withQueryValue()` and `Uri::withQueryValues()` to prevent them being interpreted as spaces
# saloonphp/saloon (3.14.2 → 4.0.0)
…
Each package becomes a top-level # heading; release entries inside reuse the single-package markdown layout.
No updated packages: all three formats emit an empty result rather than failing.
| Format | Message |
|---|---|
| Text | No updated packages found. |
| Markdown | _No updated packages found._ |
| JSON | {"total_packages": 0, "packages": []} |
Examples
Aggregate Mode (All Updated Packages)
Show changelogs for every package that changed since the previous commit:
whatsdiff changelog
Aggregate across a release range:
whatsdiff changelog --from=v1.0.0 --to=v2.0.0
Restrict the aggregate to one ecosystem and render markdown:
whatsdiff changelog --include=composer --format=markdown
JSON aggregate for downstream tooling:
whatsdiff changelog --format=json
Show Changelog for Latest Version
Display the changelog for the most recent version change in your lock file:
whatsdiff changelog symfony/console
This automatically detects the version from your composer.lock and shows the release notes.
Specific Version
View the changelog for a specific version release:
whatsdiff changelog laravel/framework 11.0.0
Version Range
See all release notes between two versions:
whatsdiff changelog symfony/console 6.0.0...6.4.0
Between Git Commits of your project
Compare package versions between two commits:
whatsdiff changelog doctrine/orm --from=abc123 --to=def456
Or between a previous commit and current state:
whatsdiff changelog guzzlehttp/guzzle --from=v1.0.0
Different Output Formats
Export changelog in different formats (see Output Formats section for examples):
# Markdown format (great for documentation)
whatsdiff changelog react --format=markdown
# JSON format (useful for automation)
whatsdiff changelog symfony/console --format=json
# Summary view (aggregated changelog)
whatsdiff changelog symfony/console --summary
Get changelog for any package even outside your project
If the package isn't in your lock files or you want to force a specific registry:
whatsdiff changelog react --type=npm
whatsdiff changelog symfony/mailer --type=composer
Option: Include Pre-releases
By default, pre-release versions are excluded. To include them:
whatsdiff changelog laravel/framework --include-prerelease
Use Cases
1. Generate Multi-Package Release Notes for a PR
After a composer update or npm update, capture changelogs for every updated package and drop them straight into your PR description:
whatsdiff changelog --from=origin/main --to=HEAD --format=markdown > pr-notes.md
Aggregate mode means a single command produces the full review surface — no need to invoke changelog once per package.
2. Review Changes Before Upgrading
Before running composer update, check what's new:
# See what's changed in the latest Laravel release
whatsdiff changelog laravel/framework
# Review all changes in a major version upgrade
whatsdiff changelog symfony/console 6.0.0...7.0.0
3. Understand Breaking Changes
Quickly identify breaking changes when debugging after an update:
whatsdiff changelog symfony/http-kernel --summary
The summary view aggregates all changes, making it easier to spot breaking changes.
4. Generate Release Notes
Extract changelogs for your own release documentation:
whatsdiff changelog doctrine/orm --format=markdown > release-notes.md
5. Code Review - Understand PR Dependencies
When reviewing a pull request that updates dependencies:
# Switch to the PR branch
git checkout feature/update-deps
# View changelogs for updated packages
whatsdiff changelog laravel/framework
whatsdiff changelog livewire/livewire
6. Audit Historical Changes
Investigate what changed in dependencies between production releases:
whatsdiff changelog symfony/security-core --from=v2.0.0 --to=v3.0.0
7. CI/CD Integration or Other tools
Use the JSON output for automation in scripts:
#!/bin/bash
echo "Dependency changelogs for this deployment:"
whatsdiff changelog laravel/framework --format=json > deployment-changes.json