git clone正常但zip下载缺文件,是因为git archive及github/gitlab zip下载会严格遵循.gitattributes中的export-ignore规则跳过匹配路径,而clone则获取完整仓库。

不是 Git 拉取失败,也不是远程分支没更新——代码“不完整”很可能是 .gitattributes 里写了 export-ignore,而你正在用 git archive 或 GitHub/GitLab 的 ZIP 下载方式获取代码。
为什么 git clone 正常但 ZIP 下载缺文件?
Git 的 clone 和 archive 是两套逻辑:clone 拉的是完整仓库(含所有 commit、分支、.gitattributes),而 archive(被 GitHub “Download ZIP”、GitLab Releases、Packagist dist 构建调用)会严格读取 .gitattributes 中的 export-ignore 行,直接跳过匹配路径。
常见现象:
- 你在 GitHub 页面点 “Download ZIP”,打开后发现没有
tests/、examples/、phpunit.xml - CI 构建用
curl -L https://github.com/xxx/yyy/archive/refs/tags/v1.2.3.zip解压后目录明显比git clone少 - 本地执行
git archive --format=zip -o test.zip HEAD得到的包也缺文件
这些都不是 bug,是 export-ignore 在生效。
怎么快速确认是不是 .gitattributes 搞的鬼?
进项目根目录,运行:
GInstall OneClick — 一键安装 GitHub 项目:规划、克隆、安装 Node 依赖、运行开发脚本。适用于想要获取 GitHubNode.js 项目的用户。
cat .gitattributes | grep export-ignore
如果输出类似:
/tests export-ignore /examples export-ignore /phpunit.xml export-ignore
那基本就是它了。再验证一下实际影响:
-
git archive --list HEAD | grep -E "(tests|examples|phpunit)"—— 若无输出,说明已被过滤 - 对比
git ls-tree -r HEAD --name-only | wc -l和git archive --list HEAD | wc -l,后者显著更少就坐实了
.gitattributes 配置中容易踩的坑
很多团队配了但没配对,导致该删的没删、不该删的被删了:
- 路径开头不加
/:写tests export-ignore会误删mytests.php或src/MyTests,必须写/tests export-ignore - 重复或冲突规则:比如同时有
/tests export-ignore和/tests/ExampleTest.php -export-ignore,后者无效(Git 不支持取消 ignore) - 把
.gitattributes自己写进了export-ignore:虽然它最终不会被打包,但编辑时容易误删,建议显式排除:.gitattributes export-ignore - Windows 换行符混入:用
dos2unix .gitattributes清理,否则某些 Git 版本会忽略整行
需要保留某些文件但又想用 export-ignore?
Git 不支持“白名单”式归档,但可以靠顺序和前缀控制:
-
export-ignore是前缀匹配,不是 glob,所以/tests/Unit/不会匹配/tests/Integration/—— 如果只想删单元测试,得分别写两行 - 想保留
/tests/bootstrap.php?不行,/tests export-ignore会一并过滤整个目录;只能改路径,比如挪到/stubs/tests-bootstrap.php再单独放行(不推荐) - 真正需要精细控制时,别依赖
export-ignore,改用composer archive+archive.exclude配置,它支持数组精确声明,且只作用于 Composer 打包场景
最麻烦的情况是:你依赖的第三方包自己配了 export-ignore,导致 vendor/xxx/yyy 里缺文件——这时你无法修改它的 .gitattributes,只能联系维护者,或换用 source 安装("preferred-install": {"xxx/yyy": "source"}),但会失去 dist 包的校验和优势。










