GitHub Actions pip 缓存总失效?我踩过最深的 4 个坑

封面图

# GitHub Actions pip 缓存总失效?我踩过最深的 4 个坑

GitHub Actions 的 pip 缓存用不对,每次 CI 都重新下载几千个包,多花 1-3 分钟。本文记录我实际踩过的 4 个缓存失效场景,给出可直接复制的配置代码。

坑 1:hash 值作为 key,每次依赖变化都失效

错误配置

- name: Cache pip packages
  uses: actions/cache@v4
  with:
    path: ~/.cache/pip
    key: pip-${{ hashFiles('**/requirements.txt') }}

问题分析

actions/cache@v4 在某些 Runner 版本下,key 的 hash 算法不稳定,每次生成的 key 都不一样,缓存永远命中不了。

另一个问题:Python 版本更新(3.11 → 3.12),即使 requirements.txt 没变,pip 包编译版本也不兼容,但缓存 key 里没有 Python 版本信息。

正确配置

- name: Cache pip packages
  uses: actions/cache@v4
  with:
    path: ~/.cache/pip
    key: pip-${{ runner.os }}-${{ hashFiles('**/requirements.txt') }}-${{ hashFiles('.github/workflows/ci.yml') }}
    restore-keys: |
      pip-${{ runner.os }}-${{ hashFiles('**/requirements.txt') }}-
      pip-${{ runner.os }}-

restore-keys 是关键:精确 key 匹配不到时,模糊匹配会尝试 fallback,最大化缓存利用率。

坑 2:用了 setup-python 但没指定固定版本

错误配置

- uses: actions/setup-python@v5
  with:
    python-version: '3.x'   # ❌ 动态版本,每次可能不同

问题分析

python-version: '3.x' 会自动解析到最新的 3.x 版本。Runner 镜像更新后,可能从 3.11 变成 3.12,pip 包编译缓存就不通用了。

正确配置(推荐)

- uses: actions/setup-python@v5
  with:
    python-version: '3.11'   # ✅ 固定版本
    cache: 'pip'             # ✅ setup-python 内置缓存

setup-python@v5 自带 pip 缓存支持,配置最简洁。

坑 3:多 Python 版本矩阵构建,缓存 key 没有隔离

错误场景

strategy:
  matrix:
    python-version: ['3.10', '3.11', '3.12']
steps:
  - uses: actions/setup-python@v5
    with:
      python-version: ${{ matrix.python-version }}
      cache: 'pip'   # ✅ setup-python 已自动按版本隔离

问题分析

以为"3.10 的缓存 3.11 也能用"——错。pip 包有平台差异,不同 Python 版本的包也不完全兼容,必须独立缓存。

实际上用 setup-pythoncache: 'pip' 已经自动按 Python 版本隔离了,但如果用 actions/cache 手动管理,就需要把 python-version 加入 key。

正确配置

- name: Cache pip packages
  uses: actions/cache@v4
  with:
    path: ~/.cache/pip
    key: pip-${{ runner.os }}-${{ matrix.python-version }}-${{ hashFiles('requirements.txt') }}

坑 4:requirements.txt 里的 git 引用或相对路径让 hash 不稳定

不稳定写法

requirements.txt:
  -e git+https://github.com/user/repo.git@main#egg=pkg
  -r ./local_requirements.txt
  ./some_package/

问题分析

  • git+https 引用 @main,每次 clone 的 commit hash 可能不同
  • 相对路径在不同 CI 环境下的路径解析可能不一致
  • 本地包 ./some_package/ 的 hash 会随包内容变化

解决方案

- name: Generate stable lock hash
  run: |
    cat requirements.txt | grep -v "^\\-e" | grep -v "^\\-r" | grep -v "^\\./" > requirements-stable.txt
    echo "HASH=$(md5sum requirements-stable.txt | cut -d' ' -f1)" >> $GITHUB_OUTPUT

- name: Cache pip packages
  uses: actions/cache@v4
  with:
    path: ~/.cache/pip
    key: pip-${{ runner.os }}-${{ hashFiles('requirements-stable.txt') }}

只对稳定依赖做 hash,排除 git 引用和相对路径。

完整正确配置示例

name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ['3.10', '3.11', '3.12']

    steps:
      - uses: actions/checkout@v4

      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}
          cache: 'pip'
          cache-dependency-path: 'requirements.txt'

      - name: Install dependencies
        run: pip install -r requirements.txt

      - name: Run tests
        run: pytest tests/

cache-dependency-path 显式指定用 requirements.txt 的 hash 做缓存 key,比默认行为更可控。

验证缓存是否生效

在 Action 日志里搜 cache-hit

  • Cache hit: false — 缓存未命中
  • Cache hit: true — 缓存命中

如果 cache-hit: false,先检查:requirements.txt 是否有变化、Python 版本是否改变、Runner OS 是否改变。

总结

原因 修复方案
hash 不稳定 动态版本或 git 引用 固定 Python 版本,过滤不稳定依赖
key 缺少 OS 不同 OS 的包不通用 key 里加 runner.os
用了 actions/cache 而非 setup-python 配置复杂容易出错 优先用 setup-python 内置缓存
多版本缓存未隔离 每个版本需要独立 key key 里加 python-version

核心原则:缓存 key 必须包含所有影响依赖解析的变量(OS + Python 版本 + 稳定的依赖文件 hash),缺任何一个都会导致缓存失效。

© 版权声明
THE END
喜欢就支持一下吧
点赞6 分享