--prefer-source是提PR的硬性前提,因它强制git clone保留.git目录和完整工作区,否则vendor中无.git,无法执行git status、checkout、commit等协作操作。

想给 Composer 包提 PR,--prefer-source 不是可选项,是硬性前提;没它,vendor/ 里压根没有 .git,你连 git status 都跑不起来,更别说切分支、写测试、推代码。
为什么 --prefer-source 是协作起点
Composer 默认用 --prefer-dist 下 zip 包,解压后只有 PHP 文件,vendor/foo/bar 目录下 ls -A | grep git 返回空——这不是“源码”,是快照。贡献的本质是参与 Git 协作流程,不是编辑一堆静态文件。
--prefer-source 强制执行 git clone,完整保留工作区、历史提交、远程地址和 .gitignore 规则。这是你 fork → clone → modify → push 的最小可行环境。
- 包作者没声明
"source"字段(只写了"dist"),--prefer-source会被静默忽略,vendor里依旧没.git - 你 fork 后改了 GitHub URL,但没在
repositories里声明,Composer 仍会尝试从原作者地址克隆,失败后 fallback 到 dist - 本地没配 SSH key,而包用的是
git@github.com:地址,克隆会卡住或报 permission denied
怎么确认 --prefer-source 真生效了
别靠猜。进 vendor/vendorname/packagename 目录,直接验证:
- 运行
git remote -v:输出必须是你自己的 fork 地址,不是原作者的;如果不是,立刻git remote set-url origin https://github.com/yourname/packagename.git - 运行
composer show vendorname/packagename -f=source:应返回类似{"url":"https://github.com/yourname/packagename.git","type":"git"};如果为空,说明没走 source 流程 - 运行
ls -A | grep '\.git$':必须有结果;没有就等于还没真正开始协作
改完代码后怎么正确提交到自己 fork
确认好远程地址后,流程回归标准 Git 操作,但有几个容易漏的关键点:
- 先
git checkout -b fix/xxx新建分支,别直接在main上改 - 改完文件后,用
git add -f而不是git add—— 因为vendor/下很多文件被项目级.gitignore拦了(比如 IDE 配置、生成的 autoload),不加-f就不会进暂存区 -
git commit -m "fix: typo in README.md",描述要具体,避免 “update” 或 “fix bug” 这类模糊信息 -
git push origin fix/xxx推送到你自己的 fork,不是原仓库
常见失效场景和绕过方式
有些包即使加了 --prefer-source 也拿不到 .git,往往卡在源头配置上:
- 包的
composer.json里缺失"source"字段,只有"dist"→ 找原作者提 issue,或换用path类型仓库本地调试 - 你 fork 后改了
composer.json的"name",但没git push到远程 → Packagist 不认,Composer 也拉不到你的变更 - 想基于 dev 分支开发,但
composer require vendor/package:dev-main --prefer-source报错 → 检查该分支是否存在、是否含合法composer.json,且"name"字段未被意外修改
真正卡住的地方,从来不是命令怎么敲,而是 vendor/ 目录下有没有那个 .git 子目录——它不在,所有后续操作都是空中楼阁。











