尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

GitHub Actions中actions/checkout完全指南:原理、参数与常见问题

GitHub Actions中actions/checkout完全指南:原理、参数与常见问题 actions/checkout是 GitHub Actions 中最常用的 Action 之一几乎所有 CI 工作流的第一步都是从它开始的。但对于刚接触 GitHub Actions 的开发者来说checkout 到底做了什么、有哪些参数需要关注、为什么有时候拉下来的代码不完整、子模块要怎么处理这些问题往往散落在各个 issue 和博客里不成体系。本文会从核心概念讲起结合完整示例、参数说明和常见报错带你彻底搞懂 GitHub Actions 中 checkout 的用法和原理并与 Git 本地的git checkout命令做区分避免混淆。1. 背景与核心概念1.1 什么是 actions/checkoutactions/checkout是 GitHub 官方提供的一个 Action它的作用是在 GitHub Actions 的运行环境中拉取当前仓库的代码让后续的 CI 步骤能够基于这份代码执行构建、测试、打包等操作。可以这样理解GitHub Actions 的工作流运行在一个独立的虚拟机上这个环境一开始是空白的、和我们本地开发环境无关的。即使工作流是因为某个仓库的 push 事件触发的运行环境本身也不会自动携带仓库代码。我们需要显式地执行 checkout 动作才能把代码“取”到 runner 中。因此几乎每个 GitHub Actions 工作流的第一段都是steps: - name: 拉取代码 uses: actions/checkoutv4这段配置的含义是让当前 job 使用actions/checkoutv4这个 Action把仓库代码检出到 runner 的工作目录中。1.2 checkout 解决了什么问题GitHub Actions 的定位是自动化任务执行平台。它需要的是可重复、可控、干净的执行环境。如果系统默认把仓库代码自动挂载到每个环境里反而会带来几个问题不是所有工作流都需要仓库代码自动检出会浪费时间和存储。不同工作流可能需要在不同分支、不同 commit 上执行自动检出无法灵活指定。runner 环境的镜像需要保持通用性内置所有仓库代码不现实。actions/checkout把“是否拉取代码”“拉取哪个分支”“拉取多深的历史”这些选择权交给了工作流编写者。这种显式声明的方式更符合 CI/CD 的工程化思路也让工作流的行为更可预测。1.3 checkout 和 git clone 的区别很多人会问checkout 不就是 git clone 吗两者确实都是拉取代码但存在几个明显差异对比项git cloneactions/checkout操作主体在本地终端手动执行在 GitHub Actions runner 中自动执行身份认证依赖本地 SSH key 或凭据自动使用 GitHub 提供的 GITHUB_TOKEN参数能力需要自己组合多个参数提供封装好的 Action 参数分支切换clone 后需要手动 checkout可直接指定要检出的 ref历史深度默认为完整历史可通过 fetch-depth 控制子模块处理需要手动执行相关命令可通过 submodules 参数自动处理actions/checkout本质上是在 runner 中执行类似 git clone 的操作但它针对 CI 场景做了很多封装比如自动处理认证、优化检出效率、支持稀疏检出、支持 GitHub 托管 runner 的特殊环境变量等。1.4 常见使用场景actions/checkout在以下场景中使用频率较高每次 push 代码后自动执行测试。Pull Request 创建或同步时运行静态检查。发布版本时拉取指定 tag 的代码进行构建。多仓库协作时在主仓库工作流中拉取其他仓库代码。需要同时拉取多个子模块的文档站或 monorepo 项目。2. 环境准备与版本说明2.1 GitHub Actions 基础环境在使用actions/checkout之前需要确保你已经具备以下条件一个 GitHub 账号和仓库。仓库中已启用 GitHub Actions默认开启。本地有 Git 基础使用经验。了解 YAML 的基本语法。GitHub 提供了两类 runnerGitHub 托管的 runner例如ubuntu-latest、windows-latest、macos-latest。自托管 runner即自己搭建的运行环境。actions/checkout在这两类 runner 上都可以使用但配置细节略有差异。本文示例以 GitHub 托管的ubuntu-latest为例这部分配置对大多数项目都适用。2.2 actions/checkout 版本说明actions/checkout目前已经历了多个大版本使用最广的版本是v3和v4。版本主要变化v2基于 Node.js 运行成为主流版本v3适配 Node 16继续兼容大部分项目v4适配 Node 20参数模型更清晰安全性和性能有改进在实际项目中建议使用v4或保持与项目约定一致的 tag。这里的 tag 是大版本号GitHub Actions 会自动解析到该大版本的最新 release不需要锁死小版本。如果团队对可复现性要求较高也可以锁定为具体的 release tag例如类似actions/checkoutv4.1.1的写法。但需要特别注意的是Actions 的 release 版本会持续更新锁定小版本后应及时关注官方更新避免错过安全修复。2.3 示例项目结构本文后续的实战案例会基于一个简单的 Node.js 项目目录结构如下github-actions-checkout-demo/ ├── .github │ └── workflows │ └── ci.yml ├── package.json ├── index.js └── README.md其中ci.yml是关键它定义了整个 GitHub Actions 工作流。其他文件是一个最小可运行的 Node.js 项目方便我们验证 checkout 的效果。3. checkout 操作原理拆解3.1 checkout 的核心逻辑actions/checkout在 runner 中做了以下几件核心事情根据repository参数确定要拉取的仓库地址。根据ref参数确定要检出的分支、tag 或 commit SHA。配置 Git 凭据使用GITHUB_TOKEN或自定义 token 完成身份认证。克隆代码到path参数指定的目录。根据需要处理子模块、LFS 文件、稀疏检出等扩展选项。切换到目标 ref确保当前工作区与指定提交一致。从底层看checkout 的过程和我们在终端手动执行的 Git 命令很相似但它在 runner 环境中自动完成了认证和环境准备。3.2 默认参数说明actions/checkout提供了大量参数。下面我们先看几个最重要的3.2.1 repository指定要拉取的仓库默认值是当前仓库。- uses: actions/checkoutv4 with: repository: your-github-name/repo-name当工作流在仓库 A 中却需要拉取仓库 B 的代码时可以通过这个参数切换。3.2.2 ref指定要检出的分支、tag 或 commit SHA。默认情况下GitHub Actions 会根据触发事件自动判断。例如 push 事件会检出对应分支的最新提交pull_request 事件会检出 PR 的合并结果。也可以手动指定- uses: actions/checkoutv4 with: ref: main或- uses: actions/checkoutv4 with: ref: v1.2.03.2.3 fetch-depth控制 Git 历史的获取深度。默认值是 1也就是只拉取最新的一个提交。这在大多数 CI 场景中已经够用能显著加快 checkout 速度。如果需要完整历史可以设置为0- uses: actions/checkoutv4 with: fetch-depth: 0如果需要最近几个提交比如做代码扫描或版本计算可以设置为具体数字例如fetch-depth: 10。3.2.4 path指定代码检出到 runner 的哪个目录默认是当前工作目录$GITHUB_WORKSPACE。- uses: actions/checkoutv4 with: path: my-code设置后后续步骤需要进入my-code目录才能操作代码。3.2.5 token指定用于认证的 GitHub token默认是${{ github.token }}也就是 GITHUB_TOKEN。这个 token 由 GitHub Actions 自动生成权限由工作流的permissions配置决定。如果需要拉取私有仓库或在当前仓库中 push 代码可能需要自定义 token- uses: actions/checkoutv4 with: token: ${{ secrets.MY_PAT }}3.2.6 submodules控制子模块的拉取方式。默认值为false即不拉取子模块。如果项目使用了 submodule需要设置为true或recursive- uses: actions/checkoutv4 with: submodules: recursiverecursive会递归拉取所有嵌套子模块。3.2.7 lfs控制是否拉取 Git LFS 大文件。默认是false- uses: actions/checkoutv4 with: lfs: true3.2.8 sparse-checkout用于稀疏检出只在需要部分目录时使用。这个参数在大型 monorepo 项目中很实用。- uses: actions/checkoutv4 with: sparse-checkout: | src tests3.3 常见误区3.3.1 误认为 checkout 会自动切换分支actions/checkout会切换到目标 ref但它不受本地git checkout命令一样的“分支切换”语义影响。在 Actions 环境中检出的是某个具体的提交状态后续步骤中直接运行git branch可能看到的是 detached HEAD 状态。这通常是正常的因为 CI 只需要代码内容并不关心你当前在哪个分支上工作。3.3.2 忽略 fetch-depth 对版本号计算的影响很多项目在 CI 中根据 Git tag 计算版本号。此时如果fetch-depth为 1可能无法取得最近的 tag导致版本号错误。这种情况下需要将fetch-depth设置为0。3.3.3 把 actions/checkout 和 git checkout 混为一谈这个点非常常见。Git 命令git checkout用于本地分支切换或文件恢复而actions/checkout是 GitHub Actions 的一个 Action两者解决的问题完全不同。在写工作流时使用的是 GitHub Actions 的语法在写 shell 命令时才会用到git checkout。理解这个区别对排查问题很有帮助。4. 完整实战案例下面我们从头开始构建一个 GitHub Actions 工作流逐步演示actions/checkout的使用方法。4.1 创建项目结构先在 GitHub 上创建一个新仓库然后在本地把项目克隆下来。仓库名称可以命名为github-actions-checkout-demo。在本地创建以下文件package.json{ name: github-actions-checkout-demo, version: 1.0.0, description: A simple demo for actions/checkout, main: index.js, scripts: { test: node index.js } }index.jsconsole.log(Hello from GitHub Actions checkout demo!);README.md写入简单的项目说明。4.2 编写第一个工作流在项目根目录创建.github/workflows/ci.yml内容如下name: CI on: push: branches: [ main ] pull_request: branches: [ main ] jobs: build: runs-on: ubuntu-latest steps: - name: 拉取代码 uses: actions/checkoutv4 - name: 查看检出后的文件 run: | pwd ls -la - name: 运行测试 run: npm test将这个文件提交并推送到 GitHub 后打开仓库的 Actions 页面可以看到工作流开始执行。4.3 运行与验证工作流执行时你会看到拉取代码这一步使用了actions/checkoutv4。这一步完成后后续步骤就能访问到仓库中的代码。查看检出后的文件步骤会输出当前工作目录和文件列表结果类似/home/runner/work/github-actions-checkout-demo/github-actions-checkout-demo total 16 drwxr-xr-x 3 runner docker 4096 ... drwxr-xr-x 3 runner docker 4096 ... -rw-r--r-- 1 runner docker 76 ... README.md drwxr-xr-x 2 runner docker 4096 ... index.js drwxr-xr-x 2 runner docker 4096 ... package.json这说明 checkout 成功地把仓库代码放到了 runner 的工作目录中。4.4 使用参数控制检出行为下面我们扩展工作流加入更丰富的 checkout 参数。4.4.1 拉取指定分支steps: - name: 拉取 main 分支 uses: actions/checkoutv4 with: ref: main这种方式适合手动触发的 workflow_dispatch 场景或者需要固定分支的发布流程。4.4.2 拉取完整历史steps: - name: 拉取完整 Git 历史 uses: actions/checkoutv4 with: fetch-depth: 0在需要根据 Git tag 生成版本号、统计提交数量、执行某些需要历史信息的扫描工具时需要这样配置。4.4.3 检出到指定目录steps: - name: 拉取代码到 build 目录 uses: actions/checkoutv4 with: path: build - name: 进入目录查看文件 run: ls -la build当工作流需要同时检出多个仓库代码时这个参数特别有用。例如steps: - name: 拉取主仓库代码 uses: actions/checkoutv4 with: path: main-repo - name: 拉取工具仓库代码 uses: actions/checkoutv4 with: repository: your-name/tool-repo path: tool-repo4.4.4 处理子模块如果项目使用 submodule需要在 checkout 时指定steps: - name: 拉取代码并初始化子模块 uses: actions/checkoutv4 with: submodules: recursive配置了submodules: recursive后checkout 会自动运行git submodule sync --recursive和git submodule update --init --recursive不需要再手动执行额外的 shell 命令。4.5 完整的多场景工作流参考下面是一个相对完整的示例展示了多个参数的组合使用name: Full Checkout Demo on: workflow_dispatch: jobs: demo: runs-on: ubuntu-latest steps: - name: 检出主仓库代码完整历史 uses: actions/checkoutv4 with: repository: your-name/github-actions-checkout-demo ref: main fetch-depth: 0 path: app - name: 显示检出目录 run: ls -la app - name: 显示当前 Git 提交信息 run: git -C app log --oneline -5这个工作流可以通过仓库 Actions 页面的Run workflow按钮手动触发。它演示了如何指定仓库、分支、获取完整历史以及将代码检出到自定义目录。5. 常见问题与排查思路5.1 常见报错一览问题现象常见原因解决思路Repository not foundtoken 没有权限访问仓库确认使用正确的 token检查仓库名称和权限fatal: unable to access ...网络问题或认证失败检查网络确认 token 有效自托管 runner 检查代理配置检出后模块找不到子模块未初始化设置submodules: recursiveGit tag 无法获取fetch-depth 为 1设置fetch-depth: 0代码不在期望目录path 参数设置影响检查 path 参数后续步骤切换到对应目录Permission deniedGITHUB_TOKEN 权限不足调整工作流 permissions 或使用自定义 tokencheckout 卡住或超时仓库过大或网络慢使用稀疏检出、设置更大的 timeout或检查 runner 网络5.2 拉取私有仓库失败如果当前工作流需要拉取另一个私有仓库的代码甚至还需要在当前仓库中使用私有 Action那 checkout 时依赖的默认 GITHUB_TOKEN 可能权限不够。常见做法是创建一个 Personal Access Token在仓库的 Secrets 中保存然后在 checkout 时引用- uses: actions/checkoutv4 with: repository: your-name/private-repo token: ${{ secrets.MY_PAT }}需要特别注意的是个人访问令牌的权限比较大建议使用 GitHub App 的 token 或GITHUB_TOKEN配合精细化的permissions配置避免长期使用权限较大的个人令牌。5.3 checkout 的 ref 参数并非总是生效ref参数在大多数情况下都能正确指定分支、tag 或 commit但如果你同时指定了repository参数并且repository指向的是当前仓库行为与默认一致。如果指向其他仓库需要确认目标仓库中确实存在这个 ref。另外在pull_request事件中默认 checkout 的是 PR 合并后的提交而不是 PR 源分支的最新提交。这是 Actions 的设计行为目的是模拟合并后的状态。如果你需要 checkout 源分支可以依赖github上下文中的参数自行指定- uses: actions/checkoutv4 with: ref: ${{ github.event.pull_request.head.sha }}但要注意这种情况下需要确认 token 有权限访问源分支所在的仓库。5.4 子模块拉取失败子模块拉取失败的常见原因有两个子模块是私有仓库checkout 时使用的 token 没有权限。子模块内容较大默认的 fetch 策略超时。解决方案是在 checkout 时传入有权限的 token- uses: actions/checkoutv4 with: submodules: recursive token: ${{ secrets.MY_PAT }}如果子模块中还嵌套了子模块需要使用recursive而不是true。5.5 LFS 文件未拉取如果仓库使用了 Git LFS并且 CI 构建需要这些大文件需要在 checkout 时开启 LFS- uses: actions/checkoutv4 with: lfs: true注意开启 LFS 会拉取大量数据可能增加整体构建时间。如果构建不需要 LFS 文件保持默认关闭即可这样可以加快 checkout 速度。5.6 自托管 runner 的注意事项在自托管 runner 上使用actions/checkout时需要确保 runner 环境中已经安装 Git并且 Git 版本足够新。部分旧版 Git 可能无法正确处理某些 GitHub 的新特性。如果 runner 所在环境需要代理访问外部网络还需要检查代理配置是否会影响 checkout 过程中的 HTTPS 请求。6. 最佳实践与工程建议6.1 尽量使用默认参数对于大多数项目默认的actions/checkoutv4就能满足需求。默认fetch-depth: 1能显著减少 checkout 耗时而且大多数构建和测试命令并不需要完整历史。不要一开始就把fetch-depth设置为0等确实需要完整历史时再调整。6.2 重视 token 权限最小化actions/checkout默认使用GITHUB_TOKEN而这个 token 的权限范围由工作流顶部的permissions决定。建议在工作流中显式声明权限而不是依赖仓库全局设置。例如permissions: contents: read如果 checkout 后还需要在当前仓库中提交代码例如自动生成文档并推送则需要声明contents: write。此时要格外小心避免工作流在每次 push 时再次触发自身形成循环。6.3 在需要时使用稀疏检出如果你的仓库很大而 CI 只需要其中部分目录可以考虑使用sparse-checkout。这个功能在 monorepo 架构下能大幅减少检出耗时。- uses: actions/checkoutv4 with: sparse-checkout: | packages/app packages/shared需要注意的是稀疏检出后git status、git diff等操作可能只反映已检出的文件某些工具可能因此表现异常。6.4 根据事件类型合理选择 ref在写工作流时默认 checkout 逻辑已经能覆盖绝大多数场景。但如果你的工作流需要更复杂的引用关系建议先理解github上下文中的几个关键字段字段含义github.sha触发工作流的 commit SHAgithub.ref触发工作流的分支或 taggithub.event.pull_request.head.shaPR 源分支的最新 commitgithub.event.pull_request.base.shaPR 目标分支的最新 commit合理使用这些字段可以让 checkout 更精确地定位到需要分析的提交。6.5 避免在 checkout 后修改 Git 配置导致问题有些项目会在工作流中手动执行git config user.name或git config user.email。这些操作在本地没有问题但在 CI runner 中如果后续有自动提交需求需要正确设置这些值。建议通过环境变量或专门的步骤来管理不要在 checkout 之前强行修改全局 Git 配置以免影响其他步骤。6.6 缓存与 checkout 的顺序在 GitHub Actions 中缓存恢复和 checkout 的顺序会影响效率。如果用了actions/cache恢复依赖缓存并且缓存内容不依赖代码内容通常可以先恢复缓存再 checkout。如果缓存 key 中包含 commit SHA那么必须先 checkout才能知道当前的 SHA然后构造缓存 key。这里给出一个常见的组合示例steps: - name: 拉取代码 uses: actions/checkoutv4 - name: 恢复 npm 缓存 uses: actions/cachev4 with: path: ~/.npm key: npm-${{ hashFiles(package-lock.json) }}6.7 关注 checkout 和 git checkout 的语义区别回到文章开始时提到的混淆点actions/checkout解决的是“在 CI 环境中检出代码”的问题git checkout解决的是“在本地仓库中切换分支或恢复文件”的问题。如果在一个 workflow 的run步骤里写 shell 命令需要操作 Git 时依然可以使用git checkout但在uses关键字下我们使用的是 GitHub Actions 的 Action 语法。这种区分在排查问题时非常重要。例如在 CI 日志中看到Run actions/checkoutv4这是 Action 的输出看到git checkout main才是 shell 命令的输出。理解了这一层就不会因为报错信息来自不同的层而困惑。6.8 定期关注 Action 版本更新GitHub 官方会不定期发布actions/checkout的新版本修复安全漏洞或兼容性问题。建议在 CI 中定期检查使用的版本尤其是在 GitHub 官方通知 Node.js 版本不再受支持时及时升级到新的大版本。升级时可以先在一个不关键的工作流中试用确认无误后再推广到所有仓库。不要同时调整大量配置避免问题出现时难以定位。7. 总结与学习路线本文从 GitHub Actions 中的actions/checkout入手介绍了它的核心概念、与git clone的区别、常用参数、完整实战案例以及典型报错的排查方法。同时我们重点区分了actions/checkout和 Git 本地命令git checkout的语义差异这个区分在实际排查中非常关键。如果你刚开始接触 GitHub Actions建议按以下顺序继续深入先掌握on事件触发、jobs、steps的基础写法。理解github上下文中的常用字段。尝试在一个简单项目中加入测试、构建步骤。掌握actions/upload-artifact和actions/download-artifact了解如何传递构建产物。深入学习actions/cache优化依赖安装速度。最后再研究仓库权限、环境变量、自托管 runner 等高阶内容。actions/checkout虽然只是 CI 流程中的第一步但很多构建问题其实都出在这一步。把它的参数和原理搞清楚后续的 CI 优化会顺利很多。建议你在自己的项目中多写几个小实验分别试试不同的ref、fetch-depth、path和submodules组合观察实际行为这样才能真正掌握它。如果本文对你有帮助可以收藏备用后面用到时候直接翻出来照做。
返回列表