archive-exclude 是 composer.json 根级字段,用于在 composer archive 或 Packagist 抓取时排除指定路径,仅生效于归档阶段,不支持 通配符,仅支持 * 和字面路径,且必须置于顶层。

composer.json 里用 archive-exclude 控制 zip/tar 归档内容
Composer 在执行 composer archive 或打包发布(如 GitHub Release、Packagist 自动抓取)时,会默认把整个项目目录打成压缩包。但你通常不希望把 tests/、vendor/、.git/ 或本地配置文件一起塞进去。archive-exclude 就是干这个的——它只在归档阶段生效,不影响 install 或 autoload。
-
archive-exclude是composer.json根级字段,值必须是字符串数组 - 路径匹配基于项目根目录,不支持通配符(
*),但支持**表示任意层级(例如**/Tests/) - 匹配的是路径前缀,不是 glob;所以
"tests"会排除tests/和mytests/,而"tests/"(带斜杠)才精准排除目录 - 不能排除
composer.json自身或vendor/目录(Composer 强制保留它们用于校验和依赖解析)
常见错误:忽略规则不生效?检查这几点
最常遇到“写了没用”,基本是下面几个原因:
- 拼写错误:
archive-exclude不是archive_exclude、archiveExclude或excludes - 路径没加尾部
/导致误匹配(比如想排除docs/,却写成"docs",结果documentation/也被砍了) - 用了
*(如"*.md")——Composer 不支持这种 shell-style 通配,只认**和字面路径 - 规则写在
extra或scripts里——必须放在composer.json顶层,和其他字段如name、autoload并列 - 执行的是
zip -r手动打包,而非composer archive——该配置对纯 shell 命令完全无效
实际配置示例与语义差异
以下片段可直接放进 composer.json:
{
"name": "myorg/mylib",
"archive-exclude": [
"/.git/",
"/.idea/",
"/tests/",
"/examples/",
"/CHANGELOG.md",
"**/phpunit.xml"
]
}
-
/.git/:开头的/表示从项目根开始,确保只匹配根目录下的.git/(避免误删子模块里的 .git) -
/tests/:同理,精准排除根级 tests 目录;如果项目有src/Tests/,它不受影响 -
**/phpunit.xml:匹配任意深度的 phpunit.xml 文件,适合多测试套件结构 -
/CHANGELOG.md:注意是文件,不是目录,所以不加/尾缀
替代方案:什么时候不该用 archive-exclude
如果你的目标不是 composer archive,而是 GitHub 发布资产(GitHub Releases)、Docker 构建上下文、或 CI 中的源码上传,archive-exclude 完全不参与。这时候应该用:
- GitHub:靠
.gitattributes的export-ignore(Git 本身归档机制) - Docker:用
.dockerignore,行为更可控且被广泛支持 - CI 脚本:手动
tar --exclude或rsync -a --exclude - 想彻底不让某些文件进 Git?那得用
.gitignore,和 Composer 无关
archive 命令和 Packagist 的自动源码抓取——它既不改变 Git 行为,也不影响任何其他打包工具,别指望它“一配永逸”。










