.gitattributes是精简Composer发布的首选方案,因其被git archive原生支持,优先级高于其他配置,且在Packagist自动构建dist包时必然生效;而archive.exclude仅限composer archive命令有效,CI或Packagist默认不识别。

为什么 .gitattributes 是精简 Composer 发布的首选方案
因为 Composer 在拉取 dist 包(即打 tag 后的 zip/tar.gz)时,底层调用的是 git archive。而 .gitattributes 是 Git 唯一原生支持、被 git archive 严格遵守的打包排除机制。它不依赖 Composer 版本、不触发钩子、不修改源码结构,也不需要你手动删文件——只要配置正确,打出来的包天然干净。
.gitattributes 中 export-ignore 的写法细节
常见错误是路径写错或忽略层级关系。关键点如下:
-
/tests/会排除根目录下的tests/目录(注意开头斜杠表示从仓库根开始) -
/examples和/examples/效果相同,但推荐加尾部/显式表示目录 -
/*.md排除根目录下所有 .md 文件,但不会影响docs/README.md -
/vendor不需要写——vendor/本就不该进 Git,写了也无效 - 每行一个规则,不支持通配符嵌套(如
/src/**/tests不生效)
示例 .gitattributes 文件内容:
/.gitattributes export-ignore /README.md export-ignore /tests/ export-ignore /examples/ export-ignore /phpunit.xml.dist export-ignore /composer.lock export-ignore
和 composer.json 的 archive.exclude 对比有什么区别
archive.exclude 看起来更“Composer 原生”,但实际限制很多:
- 只在执行
composer archive命令时生效;CI 自动构建或 Packagist 拉取 dist 时通常不走这个命令 - 部分旧版 Composer(
- 路径匹配逻辑不如
.gitattributes稳定,比如"*.md"可能漏掉某些大小写变体 - 如果你用 GitHub Releases 手动上传 zip,
archive.exclude完全不起作用
结论:archive.exclude 只适合本地调试或私有 CI 流程中主动调用 composer archive 的场景;对外发布的开源包,请坚持用 .gitattributes。
验证 .gitattributes 是否生效的最快方法
别等打 tag 后再看 dist 包——直接本地模拟 git archive:
git archive --format=zip --output=test-dist.zip HEAD
解压 test-dist.zip,检查是否还存在 tests/ 或 examples/。如果还在,说明:
- 文件没提交进 Git(
git add .gitattributes && git commit) - 路径写错了(比如漏了开头
/,变成tests/就只匹配当前目录下的 tests) - Git 缓存了旧属性(运行
git rm --cached -r . && git add .强制重读)
注意:这个验证必须在已 commit 的分支上运行,未暂存的 .gitattributes 不会被 git archive 读取。











