根本不是composer本身丢权限,而是不同系统对文件执行位、属主和umask处理逻辑不一致;linux/macos默认保留chmod +x,windows和部分docker镜像会抹掉它,git检出也可能丢失可执行位;vendor/bin脚本无执行权限时,应先用ls -l vendor/bin/phpunit确认,再执行chmod +x vendor/bin/*修复,windows用户直接用php vendor/bin/phpunit调用即可。

根本不是 Composer 本身丢权限,而是不同系统对文件执行位、属主和 umask 的处理逻辑不一致——Linux/macOS 默认保留 chmod +x,Windows 和部分 Docker 镜像会抹掉它,Git 仓库检出时也可能丢掉可执行位。
vendor/bin 脚本没执行权限,怎么验证和补救
先确认是不是执行位丢了:运行 ls -l vendor/bin/phpunit。如果输出是 -rw-r--r--(没有 x),说明执行位被清空了。
- 临时修复:在项目根目录下执行
chmod +x vendor/bin/* 2>/dev/null || true - 别用
find vendor/bin -type f -exec chmod +x {} \;——它会把 README、空文件也设成可执行,CI 工具可能报 warning - Windows 用户不用折腾 chmod,直接用
php vendor/bin/phpunit调用即可,无需./vendor/bin/phpunit
Composer install 后 vendor 目录属主错乱,常见于 Docker 和 macOS
Docker 容器内 UID 和宿主机不一致,或 macOS 文件系统不保存 uid/gid 元数据,导致 vendor/ 下文件属主变成 root 或 0:0。
- 查当前 UID/GID:
id -u和id -g(比如 1001) - 安装时显式指定:
composer install --uid=1001 --gid=1001 - docker-compose.yml 中避免硬编码,用环境变量注入:
user: "${UID:-1001}:${GID:-1001}" - Mac 上确保 Docker Desktop 设置里勾选了 “Use the Docker CLI from the terminal”
Git 检出后 vendor 权限异常,本质是 Git 不传执行位
Git 默认只跟踪文件内容和基本模式(644 或 755),但不会保留原始 tar 包里的精确权限位。从 Windows 提交的代码检出到 Linux,vendor/bin/xxx 很可能变成 -rw-r--r--。
- 不要依赖 Git 修权限,它做不到
- 在
composer.json的scripts里加自动修复逻辑:"post-install-cmd": ["@php -r \"if(is_dir('vendor/bin')) {foreach(glob('vendor/bin/*') as $f) {if(is_file($f) && !is_executable($f)) chmod($f, 0755);}}\""] - 该脚本只作用于
vendor/bin/下真实存在的文件,跳过目录和符号链接,不递归 - Windows 下这段 PHP 脚本无效,需单独处理或跳过
最常被忽略的是:.dockerignore 里漏掉 vendor/,导致宿主机上已损坏的 vendor/ 被复制进镜像层——此时 UID 参数和 post-install 脚本都失效,必须删掉重新构建。











