CI中vendor目录不能直接git ignore后靠composer install重装,因为无缓存时每次需完整解析下载安装,耗时5–15分钟且易受网络、限速、API配额影响;应缓存vendor目录本身,但需用含composer.lock哈希、OS、PHP版本、Composer版本及composer.json哈希的复合key确保兼容性,并配置restore-keys实现小版本降级匹配,安装时仍须执行composer install --no-interaction --prefer-dist以生成autoload等必要文件。

CI里vendor目录为什么不能直接git ignore后靠composer install重装
因为composer install在CI中没缓存时,每次都要走完整解析、下载、解压、安装流程,尤其带大量私有包或大体积扩展(如phpstan、larastan)时,5–15分钟很常见。单纯靠composer.lock保版本没用——网络抖动、Packagist限速、GitHub API配额不足都会让这步失败或变慢。
真正该缓存的是vendor/目录本身,但得避开两个坑:
-
vendor/里含绝对路径的phar、二进制软链(比如phpunit),跨机器重建可能失效 - 不同PHP版本、扩展启用状态(如
opcache、igbinary)下,vendor/内容实际不兼容
actions/cache怎么安全命中vendor缓存
关键不是缓存路径,而是缓存键(key)是否足够敏感。只用composer.lock哈希远远不够——PHP版本、Composer版本、平台配置(platform)变了,vendor也得重建。
推荐这样构造key:
composer-${{ hashFiles('**/composer.lock') }}-${{ runner.os }}-php-${{ matrix.php-version }}-composer-${{ steps.composer-version.outputs.version }}-${{ hashFiles('composer.json') }}
其中:
-
hashFiles('**/composer.lock')捕获依赖树变更 -
matrix.php-version隔离PHP ABI差异 -
steps.composer-version.outputs.version避免Composer 2.2和2.5因插件加载机制不同导致缓存污染 - 额外加
composer.json哈希,覆盖config.platform或scripts变动
restore-keys不是备选方案,是必填项
CI中首次运行肯定没缓存,但restore-keys能 fallback 到最近一次「兼容」缓存,比如PHP小版本升级(8.2.1 → 8.2.3)或Composer补丁更新(2.5.4 → 2.5.5),这些通常不影响vendor结构。
写法示例:
restore-keys: |
composer-${{ hashFiles('**/composer.lock') }}-${{ runner.os }}-php-${{ matrix.php-version }}-composer-
注意结尾的-:它会让actions/cache自动匹配所有以该前缀开头的缓存(如composer-abc123-linux-php-8.2-composer-2.5.4、composer-abc123-linux-php-8.2-composer-2.5.5),比硬写具体版本更鲁棒。
缓存后仍要跑composer install --no-interaction --prefer-dist
别用composer install --dry-run跳过安装——它不生成autoload文件,后续phpunit或phpcs会报Class not found;也别省掉--no-interaction,否则遇到需要用户确认的包(如某些MIT/GPL冲突提示)会卡住流水线。
必须保留的参数组合:
-
--no-interaction:防交互阻塞 -
--prefer-dist:强制走zip包而非git clone(CI没git凭据且更慢) - 不加
--optimize-autoloader:CI里没必要,且和缓存vendor冲突(它会改vendor/autoload.php) - 不加
--ignore-platform-reqs:除非你明确知道要绕过PHP扩展检查,否则会掩盖真实环境问题
缓存只是加速手段,不是替代正确安装流程的捷径。vendor目录里那些.lock、composer/installed.json、autoload_static.php,一个都不能少。











