Skip to main content

依赖项缓存参考

查找工作流中依赖项缓存功能的相关信息。

cache 操作使用情况

还原缓存时,cache 操作将尝试采用以下顺序:

  1. 首先,它会搜索所提供的 key 的精确匹配项。
  2. 如果未找到精确匹配项,将搜索 key 的部分匹配项。
  3. 如果仍未找到匹配项,并且你已提供 restore-keys,则会按顺序检查这些键是否存在部分匹配项。 有关详细信息,请参阅缓存键匹配

如果与提供的 key 完全匹配,则这被视为缓存命中。 如果没有缓存与提供的 key 完全匹配,则这被视为缓存失误。 在缓存失误情况下,该操作会在作业成功完成时自动创建一个新缓存。 新缓存将使用你提供的 key,并包含你在 path 中指定的文件。 有关如何处理此问题的详细信息,请参阅缓存命中和缓存失误

不能更改现有缓存的内容。 相反,可以使用新键创建新缓存。

cache 操作的输入参数

  • key必要。保存缓存时创建的密钥和用于搜索缓存的密钥。 它可以是变量、上下文值、静态字符串和函数的任何组合。 密钥最大长度为 512 个字符,密钥长度超过最大长度将导致操作失败。

  • path必要。运行程序上用于缓存或还原的路径。

    • 可以指定单个路径,也可以在单独的行上添加多个路径。 例如:

      - name: Cache Gradle packages
        uses: actions/cache@v4
        with:
          path: |
            ~/.gradle/caches
            ~/.gradle/wrapper
      
    • 可以指定目录或单个文件,并且支持 glob 模式。

    • 可以指定绝对路径或相对于工作区目录的路径。

  • restore-keys可选。包含备用还原键的字符串,每个还原键均放置在一个新行上。 如果 key 没有发生缓存命中,则按照提供的顺序依次使用这些还原键来查找和还原缓存。 例如:

    restore-keys: |
      npm-feature-${{ hashFiles('package-lock.json') }}
      npm-feature-
      npm-
    
  • enableCrossOsArchiveOptional,一个布尔值,当启用时,允许Windows运行程序保存或还原与缓存创建所用操作系统无关的缓存。 如果未设置此参数,则默认为 false。 有关详细信息,请参阅操作缓存文档中的交叉操作系统缓存

注意

建议不要在缓存路径中的文件中存储任何敏感信息,例如访问令牌或登录凭据。 具有读取访问权限的任何人都可以在存储库上创建拉取请求并访问缓存的内容。 此外,存储库的分支可以在基础分支上创建拉取请求,并在基础分支上访问缓存。

cache 操作的输出参数

  • cache-hit:一个表示找到了键的精确匹配项的布尔值。

缓存命中和缓存失误

key 与现有缓存完全匹配时,称为_缓存命中_,并且操作会将缓存的文件还原到 path 目录。

key 与现有缓存不匹配时,称为_缓存失误_,在作业成功完成时会自动创建一个新缓存。

发生缓存失误时,该操作还会搜索指定的 restore-keys 以查找任何匹配项:

  1. 如果提供 restore-keyscache 操作将按顺序搜索与 restore-keys 列表匹配的任何缓存。
    • 当存在精确匹配时,该操作会将缓存中的文件还原到 path 目录。
    • 如果没有精确匹配,操作将会搜索恢复键值的部分匹配。 当操作找到部分匹配时,最近的缓存将还原到 path 目录。
  2. cache 操作完成,作业中的下一个步骤运行。
  3. 如果作业成功完成,则操作将自动创建一个包含 path 目录内容的新缓存。

有关缓存匹配过程的更详细说明,请参阅缓存键匹配

使用 cache 操作的示例

此示例在 package-lock.json 文件中的包更改时,或运行器的操作系统更改时,创建一个新的缓存。 缓存键使用上下文和表达式生成一个键值,其中包括运行器的操作系统和 package-lock.json 文件的 SHA-256 哈希。

YAML
name: Caching with npm
on: push
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6

      - name: Cache node modules
        id: cache-npm
        uses: actions/cache@v4
        env:
          cache-name: cache-node-modules
        with:
          # npm cache files are stored in `~/.npm` on Linux/macOS
          path: ~/.npm
          key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
          restore-keys: |
            ${{ runner.os }}-build-${{ env.cache-name }}-
            ${{ runner.os }}-build-
            ${{ runner.os }}-

      - if: ${{ steps.cache-npm.outputs.cache-hit != 'true' }}
        name: List the state of node modules
        continue-on-error: true
        run: npm list

      - name: Install dependencies
        run: npm install

      - name: Build
        run: npm run build

      - name: Test
        run: npm test

使用上下文创建缓存键

缓存键可以包含任何上下文、函数、文本和运算符,这些上下文、函数、文本和运算符都受 GitHub Actions支持。 有关详细信息,请参阅 上下文参考对工作流和操作中的表达式求值

使用表达式创建 key 使你能够在依赖项更改时自动创建新缓存。

例如,可以使用可计算 npm key 文件的哈希的表达式创建 package-lock.json。 因此,当构成 package-lock.json 文件的依赖项更改时,缓存键会更改,并自动创建新缓存。

npm-${{ hashFiles('package-lock.json') }}

GitHub 计算表达式 hash "package-lock.json" 以派生最终 key结果。

npm-d5ea0750

使用 cache 操作的输出

可以使用 cache 操作的输出,以根据发生的是缓存命中还是缓存失误来执行某些操作。 找到指定 key 的缓存的精确匹配时,cache-hit 输出设置为 true

在上面的示例工作流中,有一个步骤会列出发生缓存失误时节点模块的状态:

- if: ${{ steps.cache-npm.outputs.cache-hit != 'true' }}
  name: List the state of node modules
  continue-on-error: true
  run: npm list

缓存键匹配

cache 操作首先在包含工作流运行的分支中搜索 key 和缓存_版本_的缓存命中。 如果没有命中,它将搜索 key 的前缀匹配项,如果仍然没有命中,则会搜索 restore-keys 和_版本_。 如果当前分支中仍然没有命中,cache 操作会在默认分支上重试相同步骤。 请注意,范围限制在搜索期间适用。 有关详细信息,请参阅访问缓存的限制

缓存版本是使用 path 元数据以及创建缓存时使用的压缩工具标记缓存的一种方法。 这可确保使用的工作流运行与它实际可以解压缩和使用的缓存唯一匹配。 有关详细信息,请参阅操作缓存文档中的缓存版本

通过 restore-keys,你可以指定当 key 中发生缓存失误时要使用的备用还原键列表。 您可以创建从最具体到最不具体的多个恢复键。 cache 操作按顺序搜索 restore-keys。 当键不直接匹配时,操作将搜索以恢复键为前缀的键。 如果恢复键值有多个部分匹配项,操作将返回最近创建的缓存。

使用多个恢复键值的示例

restore-keys: |
  npm-feature-${{ hashFiles('package-lock.json') }}
  npm-feature-
  npm-

运行器将计算表达式,这些表达式解析为以下 restore-keys

restore-keys: |
  npm-feature-d5ea0750
  npm-feature-
  npm-

还原键 npm-feature- 与以字符串 npm-feature- 开头的任何键匹配。 例如,npm-feature-fd3052denpm-feature-a9b253ff 这两个键都与还原键匹配。 将使用创建日期最新的缓存。 此示例中的键值按以下顺序搜索:

  1. ** npm-feature-d5ea0750 ** 匹配特定哈希。
  2. ** npm-feature- ** 匹配前缀为 npm-feature- 的缓存键。
  3. ** npm- ** 匹配前缀为 npm- 的任何键。

搜索优先级示例

key:
  npm-feature-d5ea0750
restore-keys: |
  npm-feature-
  npm-

例如,如果拉取请求包含 feature 分支,并以默认分支 (main) 为目标,则该操作将按以下顺序搜索 keyrestore-keys

  1. npm-feature-d5ea0750 分支中的键 feature
  2. npm-feature- 分支中的键 feature
  3. npm- 分支中的键 feature
  4. npm-feature-d5ea0750 分支中的键 main
  5. npm-feature- 分支中的键 main
  6. npm- 分支中的键 main

针对特定包管理器的 setup-* 操作

如果要缓存下列包管理器,则使用其各自的 setup-* 操作需要最小配置,并且将为你创建和还原依赖项缓存。

包管理器用于缓存的 setup-* 操作
npm、Yarn、pnpm
setup-node
pip、pipenv、Poetry
setup-python
Gradle、Maven
setup-java
RubyGems
setup-ruby
go.sum
setup-go
.NET NuGet
setup-dotnet

访问缓存的限制

访问限制通过在不同分支或标记之间创建逻辑边界来提供缓存隔离和安全性。 工作流运行可以还原在当前分支或默认分支(通常是 main)中创建的缓存。 如果为拉取请求触发了工作流运行,则它还可以还原在基分支中创建的缓存,包括分支存储库的基分支。 例如,如果分支 feature-b 具有基分支 feature-a,则对拉取请求触发的工作流运行将有权访问在默认 main 分支、feature-a 基分支和当前 feature-b 分支中创建的缓存。

工作流运行无法还原为子分支或同级分支创建的缓存。 例如,在父分支 feature-b 上触发的工作流运行无法访问为子分支 main 创建的缓存。 例如,为 feature-a 分支(基分支为 main)创建的缓存无法供其同级 feature-c 分支(基分支为 main)访问。 工作流运行也不能还原为不同标记名称创建的缓存。 例如,针对标记 release-a(基分支为 main)触发的工作流无法访问为标记 release-b(基分支为 main)创建的缓存。

当缓存由对拉取请求触发的工作流运行创建时,会为合并引用 (refs/pull/.../merge) 创建缓存。 因此,缓存的范围有限,只能通过重新运行拉取请求来还原。 它不能由基分支或针对该基分支的其他拉取请求还原。

存储库中的多个工作流运行可以共享缓存。 可以从同一存储库和分支的另一个工作流运行访问和还原为工作流运行中的分支创建的缓存。

低信任工作流触发器的缓存访问

某些工作流在响应事件时运行,这些事件可由对存储库没有写入访问权限的人员启动,例如分支拉取请求或问题注释。 当这些事件在默认分支的上下文中运行时,它们可能被用来写入恶意缓存,而后续权限更高的工作流会恢复并信任该缓存。 此类攻击称为 缓存中毒

为了降低此风险,只有这些工作流触发器才能在默认分支的作用域中创建或覆盖缓存:

  • push
  • workflow_dispatch
  • repository_dispatch
  • delete
  • registry_package
  • page_build
  • schedule

由任何其他最终解析到默认分支的事件触发的运行,会被授予对默认分支作用域内缓存的只读访问权限。 这些运行可以还原现有缓存,但无法创建或覆盖它们。 这包括其有效负载或发起组件可以受存储库外部的人员(例如 pull_request_targetissue_commentworkflow_run)的影响的触发器。

pull_request 事件不受影响。 由 pull_request 运行创建的缓存,其作用域已限定为合并 ref(refs/pull/.../merge),无法写入默认分支的作用域。 有关详细信息,请参阅访问缓存的限制

当具有只读缓存访问权限的运行尝试保存缓存时,缓存保存会失败,但该步骤和作业都不会失败。 工作流将继续执行,该失败会在工作流日志中记录为警告。 在这种情况下,请考虑以下事项:

  • 若要保留默认分支作用域内缓存带来的性能优势,请确保有一个受信任的工作流来持续更新缓存,例如由针对默认分支的 push 触发的 CI 构建。 然后,这些缓存条目可由低信任事件(例如 pull_request_target)触发的工作流还原。
  • 在低信任工作流中,切换到仅还原缓存操作,例如 actions/cache/restore 使预期缓存使用情况清晰,并避免工作流运行日志中的警告。

安全使用缓存的最佳做法

缓存内容未签名或验证,任何可以读取缓存的工作流运行都可以提取其内容。 提取的缓存可能会修改随后在工作流运行中执行的文件,从而导致恶意代码执行。 遵循以下做法,降低使用缓存的安全风险。

  • 不要将敏感信息存储在缓存中。 可以针对存储库打开拉取请求的任何人都可以读取基分支中的缓存内容。 不要将机密、令牌或凭据写入缓存路径。 而是将敏感值存储为机密。 请参阅“机密”。
  • 保存来自受信任触发器的缓存。 将缓存写入限制为仅适用于由受信任主体触发的工作流(通常是具有仓库写入权限的主体)。 有关强制实施的默认限制,请参阅 低信任工作流触发器的缓存访问 ,以限制哪些工作流触发器可以写入缓存。 此外,请考虑使用具有部署保护规则的环境进一步限制可修改缓存的工作流。 请参阅“管理部署环境”。
  • 遵循工作流安全最佳实践来加固工作流: 仅将缓存写入权限授予那些已针对工作流漏洞进行加固的工作流。 按照 安全使用指南 中的指导,防止工作流中的漏洞可能导致代码执行和引入恶意缓存条目。

有关保护工作流的更广泛指南,请参阅 安全使用指南

使用限制和收回政策

GitHub 对缓存存储和保留应用限制来管理存储成本并防止滥用。 了解这些限制有助于优化缓存使用情况。

默认限制

GitHub 将删除在 7 天内未访问的任何缓存条目。 可以存储的缓存数没有限制,但存储库中所有缓存的总大小有限。 默认情况下,每个存储库的限制为 10 GB,但企业所有者、组织所有者或存储库管理员可以增加此限制。 超过 10 GB 的任何使用量将计费给帐户。 仓库达到其最大缓存存储后,缓存逐出策略将按照上次访问时间的顺序,从最早到最近,依次删除缓存以释放空间。

如果超过此限制,GitHub 将保存新缓存,但会开始收回缓存,直到总大小小于存储库限制。 缓存淘汰过程可能会导致缓存抖动,即缓存以很高的频率被创建和删除。 为了减少这种情况,可以查看存储库的缓存并采取纠正措施,例如从特定工作流 中删除缓存或增加缓存大小。 此功能仅适用于已登记付款方式且通过配置缓存设置选择启用该功能的用户。 请参阅 管理缓存

可以按每个存储库每分钟最多 200 次上传的速度创建缓存条目,并按每个存储库每分钟 1500 次下载的速度下载这些条目。 如果超过此速率,则在相关速率限制重置之前,后续缓存上传或下载尝试将失败。 速率限制重置前的剩余时间会在响应的 Retry-After 标头中返回。 有关速率限制的详细信息,请参阅 GitHub Actions。

增加缓存大小

如果要降低逐出缓存条目的速率,可以在“作设置”中增加缓存的存储限制。 用户拥有的存储库可以为每个存储库配置最多 10 TB。 对于组织拥有的存储库,最大可配置限制由组织的设置决定。 对于企业拥有的组织,最大可配置限制由企业设置决定。 如果使用该存储,超出默认 10 GB 的限制将会产生额外的费用。

有关详细信息,请参见:

其他存储的使用也由为 GitHub Actions 或操作缓存存储 SKU 设置的预算控制。 如果您已配置了限制,并且超出了预算限制,则您的缓存将变为只读状态,直到您的计费状态得到解决,或者通过缓存过期或被明确删除后,使用量下降到免费的10GB限度以下。 有关如何设置预算的详细信息,请参阅 设置预算以控制按流量计费的产品的支出

将您的操作缓存存储 SKU 预算设置得低于计费周期内配置存储的总成本,可能会导致缓存频繁进入只读模式。 例如,如果 SKU 的预算为 $0,并且已将存储库的最大缓存大小配置为 20GB,则一旦存储超过免费阈值,缓存就会进入只读模式。

下面是一些示例性的每月成本,用于帮助你为 Actions 缓存存储 SKU 设定预算。

缓存大小每月成本(在充分利用的情况下)
50GB$2.80
200GB$13.30
1000GB$69.30

后续步骤

若要管理依赖项缓存,请参阅 管理缓存