如何避免GitHub PR/合并队列/推送事件中内容未变时运行CI?
GitHub CI 跨场景结果缓存方案
问题背景
我有一个GitHub CI任务,需要在**拉取请求(PR)、合并队列、推送到主分支(main)**三种场景下运行。但该CI流程成本高昂,希望避免不必要的重复执行:
- 若PR已完成CI,且合并到主分支的内容完全来自该PR,不再重复执行CI
- 主分支推送时,若内容已通过CI校验,跳过重复运行
- 必须保留三种场景的CI任务入口,用于捕获绕过PR检查直接推送主分支的情况
此前尝试用actions/cache将CI结果与提交SHA关联,但PR提交合并后主分支的SHA会改变,无法用SHA作为缓存键。除了自行哈希所有待测内容,有没有GitHub事件相关字段可跨场景用于缓存CI结果?
可行的跨场景关联方案
1. 利用Git提交的tree_sha(通用核心方案)
每个Git提交都对应一个tree对象,其SHA值是提交的文件内容快照唯一标识——只要两个提交的文件内容完全一致,无论提交SHA、作者、时间如何变化,tree_sha都相同。这个值可以跨PR、合并队列、主分支推送场景复用。
获取当前提交tree_sha的命令:
git rev-parse HEAD^{tree}
2. 结合场景字段优化缓存逻辑
- PR场景:直接用PR头部提交的
tree_sha作为缓存键,PR内容不会随主分支变化而改变,缓存可稳定复用 - 合并队列场景:如果合并队列仅包含单个PR,其最终提交的
tree_sha与PR头部的tree_sha一致,可直接复用PR的CI缓存;若为多个PR合并,tree_sha会生成新值,自动触发新CI,符合需求 - 主分支推送场景:检查推送提交的
tree_sha是否存在于PR/合并队列的CI缓存中,存在则跳过执行,不存在则触发CI(捕获绕过PR的推送)
具体CI配置思路
- 添加步骤获取当前提交的
tree_sha:- name: Get tree SHA id: get-tree-sha run: echo "tree_sha=$(git rev-parse HEAD^{tree})" >> $GITHUB_OUTPUT - 用
actions/cache以tree_sha为核心构建缓存键,同时加入环境参数避免缓存失效:- name: Restore CI result cache id: cache-ci-result uses: actions/cache@v3 with: path: ci-success.txt key: ci-result-${{ runner.os }}-${{ env.MY_ENV_VERSION }}-${{ steps.get-tree-sha.outputs.tree_sha }} - 检查缓存命中情况,跳过重复CI:
- name: Skip CI if result exists if: steps.cache-ci-result.outputs.cache-hit == 'true' run: | echo "内容已通过CI校验,跳过执行" exit 0 - 执行完整CI流程后,生成成功标记并写入缓存:
- name: Run expensive CI if: steps.cache-ci-result.outputs.cache-hit != 'true' run: | # 执行你的CI任务逻辑 touch ci-success.txt
注意事项
- 缓存键需加入环境依赖版本(如Node、Python版本),避免环境不一致导致的缓存失效
- 合并队列中多PR合并的内容会生成新的
tree_sha,自动触发CI,无需额外配置 - 直接推送主分支的内容若未经过PR CI,
tree_sha不在缓存中,会正常执行CI,满足检查需求
内容的提问来源于stack exchange,提问作者KCH
相关产品推荐
相关产品推荐

