GitHub Actions Artifact 使用教程:跨 Job 传递、归档取证与二次消费
Artifact(工作流构件)是 GitHub Actions 为每次工作流运行提供的文件存储区。Job 结束时把构建产物、测试报告、覆盖率数据上传上去,同一工作流的后续 Job 用 needs 取回,人类读者在运行页面下载排查,外部系统通过 REST API 按 ID 拉取。文件与 Runner 的临时磁盘无关:Runner 销毁后产物仍在,直到保留期结束或被手动删除。
actions/upload-artifact 当前主版本为 v7(最新 Release v7.0.1),actions/download-artifact 当前主版本为 v8(最新 Release v8.0.1)。GitHub 官方教程页面的示例代码还停留在 v4/v5 版本号,参数行为以两个 Action 仓库的 README 为准,本文按 v7/v8 编写。
前置条件
开始前确认:
- 仓库已启用 Actions,且你能向
.github/workflows/提交文件。 - 项目能在单个 Job 内产出确定性文件(构建目录、报告文件等)。
- 账户或组织的 Actions 存储配额未被占满(见"配额与保留期"一节)。
- 使用 GitHub 托管 Runner。自托管 Runner 需满足对应 Action 主版本的运行时要求。
- GitHub Enterprise Server 不适用本文主版本:官方 README 明确
upload-artifact@v4+与download-artifact@v4+尚不支持 GHES,GHES 必须退回 v3(upload 用 v3.2.2,download 用 v3)。v3 的行为模型(同名追加合并)与本文描述的不可变模型完全不同,不要混用。
Artifact 是什么:模型与边界
一条工作流里 artifact 的生命周期:
Job A 产出文件
-> upload-artifact 打包(zip)并上传
-> 存储区,归属于本次工作流运行(run)
-> 同运行的 Job B 用 needs + download-artifact 取回
-> 运行结束后:人在 UI 下载 / gh CLI / REST API 继续消费
-> 保留期到期后自动删除抓住四个特性就理解了 artifact:
- 按运行归档。Artifact 只能由上传方那次工作流运行持有,不是仓库级对象存储。运行页面底部有专门的 Artifacts 区,显示名称、大小(zip 后字节数)和 SHA-256 Digest。
- 不可变。v4 起每个 artifact 创建后不能追加或修改;同名重传会报错,除非显式
overwrite: true(覆盖后生成新 ID,旧 ID 消失)。 - 写入即终。每个 Job 最多创建 500 个 artifact;同一 Job 内不能对同一 artifact 名多次追加。
- 下载要身份。UI 链接和 API 都要求登录或携带 token,不存在免认证的公开下载直链。这一点正是 artifact 与 Releases 资产、对象存储最根本的差别。
与其他数据传递方式的分工:
| 需求 | 用什么 |
|---|---|
| Job 间传递少量字符串 | Job outputs(GITHUB_OUTPUT) |
| Job 间或运行后保留文件 | Artifact |
| 加速依赖安装的复用缓存 | actions/cache(7 天未访问即清除,每仓库默认 10 GB 上限,只按分支规则恢复) |
| 面向最终用户的免登录分发 | GitHub Release 资产或外部对象存储 |
| 秘密值 | Secrets(永远不要放进 artifact) |
最短可用路径
在仓库新建 .github/workflows/artifact-demo.yml:
name: Artifact demo
on:
push:
branches: [main]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Produce a file
run: |
mkdir -p dist
echo "built at $(date -u +%FT%TZ)" > dist/result.txt
- name: Upload
uses: actions/upload-artifact@v7
with:
name: my-dist
path: dist/
consume:
runs-on: ubuntu-latest
needs: build
steps:
- name: Download
uses: actions/download-artifact@v8
with:
name: my-dist
path: incoming
- name: Verify
run: cat incoming/result.txt成功信号:
- 运行页面底部的 Artifacts 区出现
my-dist,大小与 zip 内容相符。 consumeJob 打印出文件内容,退出码 0。- 上传步骤有
artifact-id、artifact-url、artifact-digest三个输出可用(见下文)。
同一运行内的 Job 下载不需要任何 token 配置,权限自动打通;但 consume 必须等 build 整体成功后才能拿到 artifact(needs 语义)。
上传详解:upload-artifact@v7
输入参数一览
| 输入 | 默认值 | 说明 |
|---|---|---|
path | 必填 | 文件、目录或通配符;支持多行与 ! 排除 |
name | artifact | artifact 名称,同一运行内必须唯一 |
if-no-files-found | warn | warn / error / ignore 三种空匹配行为 |
retention-days | 仓库设置 | 1–90 天;0 表示用仓库默认;上限可被仓库设置放宽 |
compression-level | 6 | 0(不压缩)到 9;大二进制建议 0 换速度 |
overwrite | false | true 时先删同名 artifact 再传(拿到新 ID) |
include-hidden-files | false | 默认跳过 . 开头的文件/目录,防止误传敏感配置 |
archive | true | false 时不打包,只允许上传单个文件,artifact 名取文件名(name 被忽略) |
输出
| 输出 | 用途 |
|---|---|
artifact-id | 全局唯一 ID,供 REST API 和 download-artifact 的 artifact-ids 使用 |
artifact-url | https://github.com/<org>/<repo>/actions/runs/<run>/artifacts/<id> 形式的链接,适合贴进 Issue/PR;要求访问者已登录 |
artifact-digest | SHA-256 摘要,供下游校验完整性 |
步骤间用 steps.<id>.outputs.*,跨 Job 先写进 jobs.<id>.outputs 再经 needs 引用。
路径与通配符
- uses: actions/upload-artifact@v7
with:
name: my-artifact
path: |
path/output/bin/
path/output/test-results
!path/**/*.tmp多路径时,artifact 内部目录结构以所有搜索路径的最近公共祖先为根;通配符之后的层级会保留,之前的层级被压平。相对路径基于当前工作目录,~ 会展开为 $HOME。以通配符开头的路径要加引号,避免被解析为 YAML 别名。
矩阵场景必须带上矩阵维度命名
v4 起 artifact 不可变、名称必须唯一,矩阵里各组合用同一个 name 会直接冲突报错:
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
steps:
- uses: actions/upload-artifact@v7
with:
name: binary-${{ matrix.os }} # 每个组合一个独立 artifact
path: my-binary文件权限会丢失
打包上传后目录变 755、文件变 644,chmod +x 的可执行位不保留。需要保留权限时先自行 tar,再用 archive: false 上传单文件,下游解 tar 恢复:
- run: tar -cvf my_files.tar path/to/dir
- uses: actions/upload-artifact@v7
with:
path: my_files.tar # artifact 名即 my_files.tar
archive: false下载详解:download-artifact@v8
输入参数一览
| 输入 | 默认值 | 说明 |
|---|---|---|
name | 空 = 下载本次运行全部 | 指定单个 artifact;与 artifact-ids 二选一 |
artifact-ids | 空 | 逗号分隔的 ID 列表,适合上游 Job 传下来的 ID |
path | $GITHUB_WORKSPACE | 目标目录,支持 ~ |
pattern | 空 | 按名称 glob 过滤;name 存在时被忽略 |
merge-multiple | false | true 把多个 artifact 解到同一目录,否则各建同名子目录 |
github-token | 内置 | 跨运行/跨仓库时必须换有权 token |
repository | 当前仓库 | 来源仓库,owner/repo |
run-id | 当前运行 | 来源运行 ID |
skip-decompress | false | 不解压,保留原始 zip/tar 文件 |
digest-mismatch | error | 下载摘要与服务器不符时:ignore / info / warn / error |
输出只有一个 download-path(实际落盘的绝对路径)。
三种典型下载
# 1. 单包到指定目录
- uses: actions/download-artifact@v8
with:
name: my-dist
path: incoming
# 2. 矩阵产物合并到同一目录
- uses: actions/download-artifact@v8
with:
pattern: binary-*
merge-multiple: true
path: all-binaries
# 3. 按上游 Job 输出的 ID 精确取包
- uses: actions/download-artifact@v8
with:
artifact-ids: ${{ needs.build.outputs.artifact-id }}注意 merge-multiple: true 时多个包平铺进同一目录,同名文件会互相覆盖;只有下载单个 artifact(按名或按 ID)时才直接解到 path 根下。
跨运行与跨仓库消费
默认权限只允许下载本次运行的 artifact。要取别的运行或别的仓库,显式提供 github-token、repository、run-id:
- uses: actions/download-artifact@v8
with:
name: release-bundle
github-token: ${{ secrets.GH_PAT }} # 需要对目标仓库有 actions:read 权限
repository: other-org/other-repo
run-id: 1234567890token 可以是带 actions:read(fine-grained)或 repo(classic)权限的 PAT,也可以用仓库 secret 中妥善限权的 token。跨仓库消费属于权限提升行为,组织策略可能直接禁止外部 token。
如果目标运行 ID 本身难以预知,社区维护的 dawidd6/action-download-artifact(当前 v24)支持按 workflow: 文件名、branch:、commit:、pr:、run_id:、name: 等条件定位最近一次匹配运行的 artifact,常用于"取主分支最新构建"的场景。该 Action 属于第三方维护,锁 commit 或版本后再引入。
本地与自动化消费
gh CLI(人工排查)
gh run download <run-id> # 下载该运行全部 artifact
gh run download <run-id> -n my-dist # 按名称
gh run download -p 'binary-*' -D ./out # 按 glob,落到 ./out每个 artifact 默认解到以名称命名的子目录;只指定单个 artifact 时直接解到当前目录。省略 <run-id> 时取的是最近一次上传的 artifact,排查旧运行时务必显式指定运行 ID。gh 用的是你登录的账户身份。
REST API(系统集成)
| 端点 | 用途 |
|---|---|
GET /repos/{owner}/{repo}/actions/artifacts | 列出仓库全部 artifact |
GET /repos/{owner}/{repo}/actions/runs/{run_id}/artifacts | 列出某次运行的 artifact |
GET /repos/{owner}/{repo}/actions/artifacts/{artifact_id} | 单个 artifact 元数据 |
GET /repos/{owner}/{repo}/actions/artifacts/{artifact_id}/{archive_format} | 下载(archive_format 只能是 zip),返回 302,真实地址在响应头 Location |
DELETE /repos/{owner}/{repo}/actions/artifacts/{artifact_id} | 删除 |
PAT(classic)需要 repo scope;fine-grained token 需要 Actions 权限的读/写。示例:
curl -L -H "Authorization: Bearer $TOKEN" \
-H "Accept: application/vnd.github+json" \
-o artifact.zip \
"https://api.github.com/repos/OWNER/REPO/actions/artifacts/1234/zip"把 upload-artifact 的 artifact-id 输出写进 Job outputs 或下游消息,系统就能精确定位某一次构建的包,不受名称复用影响。
配额与保留期
保留期
- 默认保留 90 天,到期自动删除,不可续期(只能重新上传)。
- 组织/仓库可配置保留策略:公开仓库可在 1–90 天 内设置;私有仓库可在 1–400 天 内设置。
- 工作流里的
retention-days只能设 1–90(私有仓库按仓库设置放宽后可更高),且不能超过仓库/组织的策略上限。 - 设置调整不影响存量数据,到期清理只对新数据生效。
- 2026-10-01 起,GitHub 将把同一套 Actions 保留策略扩展到 checks、workflow runs 和提交状态:超过保留期的运行记录本身也会被清理。需要长期留存的证据(审计运行、发布验证记录)要在此前导出归档,artifact 到期删除同样不可逆。
存储配额与计费
- 计划内包含的 Actions 存储(artifact 与 cache 共用):Free 500 MB、Pro 1 GB、Team 2 GB、Enterprise 50 GB。
- 公共仓库使用 GitHub 托管 Runner 的 Actions(含存储)免费。
- 存储用量按 GB-Hours 每小时累积计费;超额会持续扣费,删除 artifact 只能阻止后续累积,本账期已产生的用量仍在账单里。
- 存储量每 6–12 小时盘点一次,删了立刻再传可能仍显示超额。
- artifact 显示的体积是 zip 压缩后大小;调整
compression-level直接影响配额占用。
能基于 Artifact 做什么
以下模式都有官方文档或开源项目背书,按投入从低到高排列。
1. 构建—测试—部署流水线(官方核心场景)
build 上传可执行包,test、package、deploy 各自 needs 上游下载。同一份二进制从编译到上线不被重新构建,天然保证"测的就是发的"。部署 Job 只需下载权限,不必再有工具链,Runner 环境要求大幅降低。
2. 失败现场捕获
- uses: actions/upload-artifact@v7
if: failure()
with:
name: test-report-${{ matrix.node }}
path: |
reports/
npm-debug.log单元测试失败时把 JUnit XML、Playwright trace(用例执行轨迹)、崩溃日志上传,if: failure() 保证正常通过的构建不会多占存储。CI 变红后可下载现场文件复现,不再依赖翻日志截图。
3. 多平台产物聚合发布
矩阵 Job 各传各的 binary-linux、binary-windows、binary-macos,下游单一 Job pattern: binary-* + merge-multiple: true 收齐后统一签名、打 tag 上传 GitHub Release。官方 Pages 部署链路就是这一模式的实现:actions/upload-pages-artifact 上传特殊格式的 github-pages artifact,actions/deploy-pages 按名下载后部署——artifact 就是官方系统自己的跨 Job 数据总线。
4. 跨仓库晋级发布
构建仓库编译一次并上传签名包,多个部署仓库(staging、prod、下游产品库)用带 actions:read 的 token 按 repository + run-id 拉取同一产物部署。避免每个环境重新编译带来的差异,也让"线上跑的是哪个字节"可以用 artifact-digest 精确回答。
5. 证据归档与审批附件
合规流程把扫描报告、SBOM(软件物料清单)、覆盖率快照以短保留期上传,审批系统通过 REST API 拉取并核验 SHA-256 digest 后再放行。注意 2026-10 起的保留期扩展:真正要长期留存的证据应导出到仓库外(对象存储、文档系统),artifact 只做运输和短期取证。
6. 本地复现线上构建
gh run download 1234567890 -n my-dist -D ./debug线上行为异常时,把那次运行实际使用的构建包原样拉到本地调试,排除"重新 build 引入差异"的干扰。
不适合用 artifact 的场景
- 面向公众的免登录下载:所有 artifact 下载通道都要求身份认证,公开分发请放 Releases 资产或对象存储/CDN。
- 依赖缓存:用
actions/cache,cache 按分支规则恢复、7 天未访问即淘汰,artifact 则每次都要全量上传。 - 敏感值:对仓库有 read 权限的用户就能列出并下载 artifact,也不存在更细的内容审查;令牌、私钥、生产配置严禁入包。
- 超大文件常驻仓库:受存储配额与 GB-Hours 计费约束,大体积长期存储应放外部对象存储,artifact 里只放下载清单。
- 跨运行可变状态:artifact 按运行归档且不可变,需要"最新状态"语义时改用 Releases、Pages 或专用存储。
权限与安全边界
- 同一运行内的上传下载由 Actions 自动授权,不需要在
permissions:里声明专门 scope;upload-artifact不需要仓库写权限(产物存到 Actions 存储,不是 Git)。 - 下载其他运行/仓库的 artifact 是权限敏感操作:token 只需要
actions:read,不要在 CI 里使用带repo全权的粗粒度 token。 - artifact 的可见性只有仓库级:read 权限即可列出和下载,write 权限才能在 UI 或 API 删除,不存在比"仓库成员"更细的产物 ACL——不要把 artifact 当作访问隔离区。
- 消费第三方工作流的产物前核对
artifact-digest;下载端digest-mismatch: error是默认值,不要用warn静默完整性问题。 - fork PR 的运行无法读取主分支秘密,也默认不能跨仓库取产物;
pull_request_target执行 PR 代码的方案不要与 artifact 消费混用。
故障处理
| 症状 | 原因与处理 |
|---|---|
An artifact with name ... already exists 或上传冲突 | 矩阵/多 Job 用了同名 artifact。名称加上矩阵维度,或后发 Job 显式 overwrite: true |
下载报 Unable to find any artifacts that match the provided criteria | name/pattern 不匹配,或 artifact 属于别的运行/仓库却没传 github-token + run-id;也可能保留期已过被删除 |
| 上传成功但没有文件 | path 没匹配到任何文件且 if-no-files-found 为默认 warn;改为 error 让流水线尽早暴露 |
下载后文件丢失 chmod +x | zip 不保留权限,用"先 tar 再 archive: false"方案 |
隐藏文件(.env、.aws/)不在包里 | include-hidden-files 默认 false,确认内容无敏感信息后再开启 |
| GHES 上 Action 直接失败 | v4+ 不支持 GHES,退 v3 或迁移 GitHub Cloud |
| 下载 API 返回 302 但拿到空文件 | 没有跟随重定向,curl -L 或让 HTTP 客户端跟随 Location |
| 提示存储配额不足 | 删除过期 artifact 需等待 6–12 小时盘点生效;长期方案是缩短 retention-days、降低保留数量或外部存储 |
| 账单比预期高 | 本账期 GB-Hours 已累积,删了不退费;检查是否有大体积、长保留的例行构建 |
验收清单
上线 artifact 工作流前逐项确认:
- [ ] artifact 名称含矩阵/版本维度,无同名冲突。
- [ ] 空匹配策略设为
error(除非确属可选项)。 - [ ]
retention-days显式设置,而不是默认 90 天吃配额。 - [ ] 下游消费方校验
artifact-digest。 - [ ] 跨仓库 token 只有
actions:read最小权限。 - [ ] 包内确认无 secrets、无隐藏敏感文件。
- [ ] 面向公众的分发路径已改走 Releases 或对象存储,不依赖 artifact 链接。
参考资料
- GitHub Docs:Store and share workflow data
- GitHub Docs:Configuring the retention period for GitHub Actions artifacts and logs
- GitHub Docs:About billing for GitHub Actions
- GitHub Docs:REST API endpoints for workflow artifacts
- GitHub Docs:Cache dependencies in workflows
- GitHub Changelog:Actions retention will cover checks, workflow runs, and statuses
- actions/upload-artifact(v7.0.1)
- actions/download-artifact(v8.0.1)
- actions/deploy-pages
- dawidd6/action-download-artifact(v24)