Validate and manage .gitattributes export-ignore rules to keep your published PHP packages lean.
When you publish a PHP package to Packagist, Composer packages up every file in your repository that Git tracks — unless
you explicitly exclude it using .gitattributes export-ignore directives. That means your published distribution archive
can unintentionally include development artefacts like IDE settings, test suites, static analysis configuration, CI
workflows, and documentation. These files bloat the download size, slow down composer require, and expose internal
project structure to downstream users.
php-lean makes sure your .gitattributes export-ignore list is complete so only the source code your users need ends
up in the published distribution archive.
composer global require stolt/php-leanMake sure that the path to your global vendor binaries directory is in your $PATH. You can find it with
composer global config bin-dir --absolute.
composer require --dev stolt/php-leanInstalling as a dev dependency allows further utilisation via Composer scripts.
php-lean <COMMAND>
| Command | Description |
|---|---|
lint |
Check if all repository artefacts are export-ignored. |
create |
Add missing artefacts to the export-ignore list. |
update |
Replace the export-ignore list, preserving custom entries. |
reformat |
Reformat an existing .gitattributes file. |
validate-remote |
Validate a remote GitHub repository's .gitattributes. |
init |
Create an initial .lpv configuration file. |
refresh |
Refresh an existing .lpv file with missing preset patterns. |
tree |
Inspect the source and dist package file structure. |
Verifies that all detected repository artefacts are listed in .gitattributes export-ignore directives.
# Check the current directory
php-lean lint
# Check a specific directory
php-lean lint /path/to/project
# Show a diff of what would change
php-lean lint --diff
# Enforce strict order comparison
php-lean lint --enforce-strict-order
# Validate the actual Git archive content
php-lean lint --validate-git-archive
# Show distribution impact report
php-lean lint --report-impact--diff flag: Shows which artefacts would be added or removed from the export-ignore list, using a unified diff
format. This is useful for previewing changes before running create.
Adds any detected artefacts that are not yet in the export-ignore list. Preserves existing entries.
# Dry run: see what would be added
php-lean create --dry-run
# Apply changes
php-lean create
# Force overwrite an existing file
php-lean create --forceReplaces the entire export-ignore list with the artefacts that currently exist in the repository, merging built-in
default patterns with any custom entries already in .gitattributes. This removes stale entries (files no longer
present) and adds new ones.
# Dry run: see what would change
php-lean update --dry-run
# Apply changes
php-lean updateReformats an existing .gitattributes file for better readability.
# Dry run: see what would change
php-lean reformat --dry-run
# Sort alphabetically
php-lean reformat --sort-alphabetically
# Sort from directories to files
php-lean reformat --sort-from-directories-to-files
# Group export-ignore and non-export-ignore entries
php-lean reformat --groupAll commands support these common options and flags:
| Option / Flag | Description |
|---|---|
<directory> |
Path to project root (default: current directory) |
--glob-pattern <PATTERN> |
Custom artefact patterns, e.g. '{.*,*.md,docs/}' |
--glob-pattern-file <PATH> |
Load patterns from a file (.lpv file used automatically) |
--preset <PRESET> |
Use a predefined preset (default: PHP) |
--diff |
Show diff-style output (lint) |
--dry-run |
Preview changes without modifying files (create, update) |
--enforce-strict-order |
Enforce strict order comparison (lint) |
--enforce-alignment |
Enforce strict alignment of export-ignores (lint) |
--validate-git-archive |
Validate actual Git archive content (lint) |
--report-impact |
Show distribution impact report (lint) |
--report-stale-export-ignores |
Report export-ignores for non-existent files (lint) |
--keep-license |
Allow license file in dist archive (lint) |
--keep-glob-pattern <PATTERN> |
Keep matching files in dist archive (lint) |
--stdin-input |
Read .gitattributes content from STDIN (lint) |
--flavour <FLAVOUR> |
Export-ignore flavour: classic or negated (create) |
By default, php-lean checks for these glob patterns (defined in the PHP preset):
.* Dotfiles and directories (e.g., .github/, .idea/, .vscode/)
*.txt Text files
*.{md,MD} Markdown files (except README — see below)
*.rst reStructuredText files
*.toml TOML configuration files
*.xml XML files
*.yml YAML files
*.dist.* Distribution config files
*.lock Lock files (e.g., composer.lock)
LICENSE Generic license file
{D,d}oc* Documentation directories
{T,t}est* / {S,s}pec* Test and spec directories
AGENT.md, AGENTS.md, CLAUDE.md, ... AI assistant instruction files
.aiassistant/, .cursor/, .claude/ AI assistant directories
llms.txt, llms-full.txt AI context files
phpstan*, phpunit*, rector*, ... PHP tooling configuration
vendor* Vendor directories
Note: README.md is always kept in the distribution archive by default and is excluded from the *.{md,MD} pattern.
Other Markdown files like CHANGELOG.md, CONTRIBUTING.md, and RELEASE.md are still export-ignored.
Override them with --glob-pattern:
php-lean lint --glob-pattern '{.*,*.md,docs/}'Or create a .lpv file in your repository to persist custom patterns:
php-lean initAll commands automatically read the .gitignore file in the project directory. Artefacts already covered by
.gitignore entries are excluded from the results, since Git will not track them anyway.
lint: Will not flag artefacts that are already in.gitignore.create: Will not add artefacts that are already in.gitignoreto the export-ignore list.update: Will not include artefacts that are already in.gitignorein the new export-ignore list.
Add php-lean lint to your CI pipeline to enforce that export-ignore lists stay complete.
By adding the following to your project's composer.json, the .gitattributes file can be validated via
composer validate-gitattributes:
{
"scripts": {
"validate-gitattributes": "php-lean lint"
}
}A reusable GitHub Action is provided to validate .gitattributes files in CI workflows.
- name: Validate .gitattributes
uses: ./.github/actions/lint
with:
options: '--enforce-strict-order --enforce-alignment --diff'See the action documentation for more details.
Run the validator ad-hoc via cpx:
cpx stolt/php-lean lintAll commands auto-detect agentic runs, switching the output from human-readable text to a structured JSON object. This is useful for AI workflows or automation pipelines where machine-readable output is preferred.
export COPILOT_MODEL=1
php-lean lint{
"command": "lint",
"status": "success",
"message": "The .gitattributes file is considered valid.",
"valid": true
}Each response always includes command, status (success or failure), and message fields. Commands also include additional context-specific fields:
| Command | Additional fields on success |
|---|---|
lint |
valid, warnings (if any), expected_gitattributes_content (on failure), archive_valid, unexpected_artifacts |
create |
gitattributes_file_path |
update |
gitattributes_file_path |
init |
lpv_file_path |
refresh |
lpv_file_path |
tree |
package, tree |
This package is developed with the assistance of Artificial Intelligence (AI). AI tools are used throughout the development process, including code generation, documentation, testing, and maintenance.
While reasonable care is taken to review and validate AI-generated contributions, AI-generated code is not inherently correct, secure, or free of defects. All contributions remain subject to human review and project quality standards.
As with any software, use this package at your own risk. No guarantee is made regarding its fitness for a particular purpose, and the maintainers assume no liability for damages resulting from its use.
If you're considering contributing to this project, have a look at this repository's CONTRIBUTING.md for more advice.
This library and its CLI are licensed under the MIT license. Please see LICENSE.md for more details.
All noteworthy changes are documented in the CHANGELOG.md.
- cargo-lean — The
Rustequivalent. - py-lean — The
Pythonequivalent. - js-lean — The
JavaScriptequivalent.