composer archive默认不包含Git元数据,仅打包源码且版本号取自composer.json,与Git tag无绑定;要实现可追溯的版本化快照,须先检出tag再打包,并用git describe动态生成含tag和commit hash的文件名。

archive 命令默认不包含 Git 元数据,tag 信息不会自动写入归档
直接运行 composer archive 生成的 zip 文件里只有代码文件,.git 目录被排除,所有 tag、commit hash、分支名都丢失。这意味着你无法通过归档文件反查它对应哪个 Git 版本——哪怕你明确指定了 --version=1.2.3,这个版本号也只是压缩包内 composer.json 的字段,和 Git tag 没有绑定关系。
真正要实现“版本化快照”,得让归档内容能和某个 tag 一一对应,而不是靠人工记住“v1.2.3 对应 commit abc123”。关键动作是:先检出 tag,再执行 archive。
- 用
git checkout v1.2.3切到对应标签(推荐加--detach避免进入分离头指针警告) - 确保当前工作区干净(
git status --porcelain应无输出),否则 archive 会打包未提交的变更 - 运行
composer archive --format=zip --file=app-v1.2.3.zip,此时打包的是该 tag 确切的代码快照
如何让 archive 文件名自动带 Git tag 和 commit hash
硬编码文件名容易出错,比如打错 tag 名或漏更新版本号。更可靠的做法是用 shell 命令动态提取:
git describe --tags --exact-match 2>/dev/null || { echo "当前 HEAD 无对应 tag"; exit 1; }
TAG=$(git describe --tags --exact-match)
COMMIT=$(git rev-parse --short HEAD)
composer archive --format=zip --file="app-${TAG}-${COMMIT}.zip"这样生成的文件如 app-v1.2.3-abc123.zip,既可读又可追溯。注意:git describe --exact-match 要求当前 commit 必须打了 tag,否则失败退出,避免误打包 dev 分支。
- 不要用
git tag | tail -n1这类模糊方式——tag 可能未按语义化排序 - 如果项目使用轻量 tag(lightweight tag),
git describe仍可用;但若只用 annotated tag,效果更稳定 -
--format=tar也支持,但 tar 默认不压缩,体积大;加--format=tar.gz更实用
archive 打包时忽略 vendor 目录,但某些场景需要保留依赖快照
composer archive 默认跳过 vendor/,这是对的——生产部署不该依赖本地 vendor。但如果你要做离线构建、审计归档、或交付给无网络环境的客户,就得把依赖一起固化。
这时不能简单加 --ignore= 去掉 vendor 排除规则,因为 composer archive 不提供“强制包含”开关。可行路径只有一条:
- 先运行
composer install --no-dev --optimize-autoloader确保vendor/存在且精简 - 改用系统命令打包:
zip -r app-v1.2.3-with-vendor.zip . -x ".git/*" "node_modules/*" "tests/*" - 或者用
tar --exclude='.git' --exclude='node_modules' -czf app-v1.2.3-with-vendor.tgz .
注意:这种做法会让归档体积暴涨(几 MB → 几十 MB),且 vendor 内容受 composer.lock 约束——必须确保 lock 文件已提交并和 tag 一致,否则快照不可复现。
CI 中自动触发 archive 并上传,需区分 push tag 和 push branch
GitHub Actions 或 GitLab CI 里,on: push 事件会同时响应分支推送和 tag 推送,但你通常只希望 tag 推送才触发归档。否则每次 PR 合并都打一个包,毫无意义。
正确写法是限定事件来源:
on:
push:
tags: ['v*'] # 匹配 v1.0.0、v2.1.0-beta 等然后在 job 步骤中,先验证 tag 格式,再检出、打包、上传:
- 用
git fetch --depth=1 origin ${{ github.head_ref }}不够——tag 不在默认 fetch 范围,得加--tags或明确git fetch origin ${{ github.head_ref }} --tags - 上传到 GitHub Releases 时,用
gh release upload,注意目标 release 必须已存在(可用gh release create先建) - 如果用私有对象存储(如 S3),别把 access key 写死在脚本里,走 CI secrets 注入
$AWS_ACCESS_KEY_ID
最易忽略的一点:CI runner 默认 shallow clone(--depth=1),导致 git describe 失败。必须显式设 fetch-depth: 0 或至少 fetch-depth: 10 才能拿到 tag 历史。


















