Composer需在项目composer.json的repositories字段显式声明type为"vcs"的Gitea仓库URL(如https://gitea.example.com/org/pkg),URL须指向含合法composer.json的根目录;版本依赖Git tag(如v1.0.0)或dev-main等分支名;HTTPS方式需配套auth.json配置PAT,SSH方式需本地密钥认证;多源共存时数组顺序决定优先级,Packagist应置末尾。

Composer 本身不内置 Gitea 支持,但能通过 vcs 类型仓库直接拉取 Git 仓库里的 PHP 包——只要那个仓库根目录下有合法的 composer.json,Gitea 就只是个“带 Web 界面的 Git 服务器”,和 GitHub、GitLab 角色一致。
必须在项目 composer.json 中显式声明 repositories
很多人以为只要 Gitea 上建好仓库、打上 tag 就行,结果 composer require your-vendor/package 直接报 Could not find package。根本原因是 Composer 默认只查 Packagist,不会自动扫描你私有服务器上的仓库。
-
repositories字段必须写在你要安装依赖的那个项目的顶层composer.json里,不是私有包自己的composer.json - 格式必须是 JSON 数组,不能是对象:
[{"type": "vcs", "url": "https://gitea.example.com/your-org/your-package"}],写成{"my-repo": {...}}会静默失效 -
url必须指向仓库根目录(即含composer.json的那层),不能是网页 URL(如https://gitea.example.com/your-org/your-package/src/main/composer.json),也不能带.git后缀(虽部分场景可加,但没必要,且易出错)
SSH 和 HTTPS 认证方式怎么选
Gitea 支持 SSH 和 HTTPS 两种协议访问仓库,但 Composer 对它们的处理逻辑完全不同:SSH 走系统级密钥,HTTPS 走 auth.json 或环境变量。
- 用 SSH:
"url": "git@gitea.example.com:your-org/your-package.git",前提是本地~/.ssh/id_rsa已配好、Gitea 用户已绑定公钥,且ssh -T git@gitea.example.com能通 - 用 HTTPS:
"url": "https://gitea.example.com/your-org/your-package",必须配套auth.json,且权限必须是600:chmod 600 auth.json,内容类似:{\n "http-basic": {\n "gitea.example.com": {\n "username": "your-gitea-username",\n "password": "your-personal-access-token"\n }\n }\n} - 推荐用 Personal Access Token(PAT)代替密码,Gitea 后台 → Settings → Applications → Manage Tokens 创建,勾选
read:repository即可;不要用账号密码,Token 可随时禁用,更安全
vcs 类型下版本号完全依赖 Git tag
Composer 不读取 composer.json 里的 "version" 字段,它只认 Git 的 lightweight tag(如 v1.0.0)。没打 tag,composer require your-vendor/package:^1.0 就找不到任何稳定版本。
- 打 tag 命令:
git tag v1.0.0 && git push origin v1.0.0 - tag 名必须符合 Composer 版本约束语法,比如
1.0.0、v2.1.3、dev-main(对应分支) - 如果想让
dev-main可被 require,得确保 main 分支存在且有提交;dev-开头的分支名会被识别为开发版,不进稳定版本池 - 修改
composer.json后忘了推 tag?composer show your-vendor/package会显示可用版本列表,用来验证是否生效
多个私有源共存时顺序决定优先级
如果你同时用了 Gitea、内部 Satis 镜像、甚至另一个 GitLab,repositories 数组的顺序就是匹配顺序——Composer 从上到下扫描,第一个匹配到同名包就停,后面的同名包永远不被看到。
- 把最常用、最稳定的私有源放前面,比如 Gitea 的核心组件库
- 避免把 Packagist 放第一位(默认行为),否则私有包永远被跳过;正确做法是把它显式放在数组末尾:
"repositories": [\n {"type": "vcs", "url": "https://gitea.example.com/org/core"},\n {"type": "vcs", "url": "https://gitea.example.com/org/utils"},\n {"packagist.org": false},\n {"type": "composer", "url": "https://packagist.org/"}\n] - CI 环境建议用
COMPOSER_AUTH环境变量传入auth.json内容,避免挂载文件失败或权限问题
最容易被忽略的一点:Gitea 仓库必须公开可读(或认证后可读),且 composer.json 文件必须在 Git 的 HEAD 提交中存在——如果只在某个 feature 分支里加了 composer.json,但没合并到 main,Composer 就看不见它。











