Skip to content

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 的生命周期:

text
Job A 产出文件
  -> upload-artifact 打包(zip)并上传
    -> 存储区,归属于本次工作流运行(run)
      -> 同运行的 Job B 用 needs + download-artifact 取回
      -> 运行结束后:人在 UI 下载 / gh CLI / REST API 继续消费
        -> 保留期到期后自动删除

抓住四个特性就理解了 artifact:

  1. 按运行归档。Artifact 只能由上传方那次工作流运行持有,不是仓库级对象存储。运行页面底部有专门的 Artifacts 区,显示名称、大小(zip 后字节数)和 SHA-256 Digest。
  2. 不可变。v4 起每个 artifact 创建后不能追加或修改;同名重传会报错,除非显式 overwrite: true(覆盖后生成新 ID,旧 ID 消失)。
  3. 写入即终。每个 Job 最多创建 500 个 artifact;同一 Job 内不能对同一 artifact 名多次追加。
  4. 下载要身份。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:

yaml
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 内容相符。
  • consume Job 打印出文件内容,退出码 0。
  • 上传步骤有 artifact-id、artifact-url、artifact-digest 三个输出可用(见下文)。

同一运行内的 Job 下载不需要任何 token 配置,权限自动打通;但 consume 必须等 build 整体成功后才能拿到 artifact(needs 语义)。

上传详解:upload-artifact@v7 ​

输入参数一览 ​

输入默认值说明
path必填文件、目录或通配符;支持多行与 ! 排除
nameartifactartifact 名称,同一运行内必须唯一
if-no-files-foundwarnwarn / error / ignore 三种空匹配行为
retention-days仓库设置1–90 天;0 表示用仓库默认;上限可被仓库设置放宽
compression-level60(不压缩)到 9;大二进制建议 0 换速度
overwritefalsetrue 时先删同名 artifact 再传(拿到新 ID)
include-hidden-filesfalse默认跳过 . 开头的文件/目录,防止误传敏感配置
archivetruefalse 时不打包,只允许上传单个文件,artifact 名取文件名(name 被忽略)

输出 ​

输出用途
artifact-id全局唯一 ID,供 REST API 和 download-artifact 的 artifact-ids 使用
artifact-urlhttps://github.com/<org>/<repo>/actions/runs/<run>/artifacts/<id> 形式的链接,适合贴进 Issue/PR;要求访问者已登录
artifact-digestSHA-256 摘要,供下游校验完整性

步骤间用 steps.<id>.outputs.*,跨 Job 先写进 jobs.<id>.outputs 再经 needs 引用。

路径与通配符 ​

yaml
- 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 会直接冲突报错:

yaml
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 恢复:

yaml
- 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-multiplefalsetrue 把多个 artifact 解到同一目录,否则各建同名子目录
github-token内置跨运行/跨仓库时必须换有权 token
repository当前仓库来源仓库,owner/repo
run-id当前运行来源运行 ID
skip-decompressfalse不解压,保留原始 zip/tar 文件
digest-mismatcherror下载摘要与服务器不符时:ignore / info / warn / error

输出只有一个 download-path(实际落盘的绝对路径)。

三种典型下载 ​

yaml
# 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:

yaml
- uses: actions/download-artifact@v8
  with:
    name: release-bundle
    github-token: ${{ secrets.GH_PAT }}   # 需要对目标仓库有 actions:read 权限
    repository: other-org/other-repo
    run-id: 1234567890

token 可以是带 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(人工排查) ​

bash
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 权限的读/写。示例:

bash
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. 失败现场捕获 ​

yaml
- 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. 本地复现线上构建 ​

bash
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 criterianame/pattern 不匹配,或 artifact 属于别的运行/仓库却没传 github-token + run-id;也可能保留期已过被删除
上传成功但没有文件path 没匹配到任何文件且 if-no-files-found 为默认 warn;改为 error 让流水线尽早暴露
下载后文件丢失 chmod +xzip 不保留权限,用"先 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 链接。

参考资料 ​

全部公开文章由同一个站点构建和发布。