GitLab CI/CD 与 GitHub Actions 都可以自动构建、测试、发布和部署代码。两者用仓库中的 YAML 描述工作流程,流程包含任务,任务包含顺序执行的步骤,并支持托管或自托管的运行器。迁移的关键是把执行环境、触发条件、任务依赖和数据传递分别映射清楚。
以下对照保留官方示例。标为“配置片段”的代码不是完整工作流;GitHub Actions 完整文件放在 .github/workflows/ 下,还需要 on 触发器、jobs 容器及每个任务的运行环境。这里只进行静态核对,未运行 CI。
任务:script 与 run
两种系统的任务都可以包含顺序执行的脚本,并分配到独立机器或容器。同一阶段内且没有依赖限制的任务可以并行;GitLab 的阶段与 GitHub 的 needs 会进一步约束顺序。GitLab 用 script 写命令,GitHub 在步骤中用 run。
GitLab CI/CD:
job1:
variables:
GIT_CHECKOUT: "true"
script:
- echo "Run your script here"
GitHub Actions 配置片段:
jobs:
job1:
steps:
- uses: actions/checkout@v6
- run: echo "Run your script here"
源例省略了运行环境与触发器。下面补成一个手动触发的完整 GitHub 工作流;checkout 获取仓库内容,不会由 run 自动完成:
name: migration-demo
on:
workflow_dispatch:
jobs:
job1:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- run: echo "Run your script here"
GitHub Enterprise Server 等环境应先确认可用运行器;不要把 ubuntu-latest 等 GitHub 托管标签理解为所有部署都提供的机器。
运行器:tags 与 runs-on
GitLab 根据 tags 选择已经注册且标签匹配的运行器。GitHub 根据 runs-on 选择托管标签或自托管标签;不能只把标签字符串照搬,实际运行器必须存在并支持脚本。
GitLab CI/CD:
windows_job:
tags:
- windows
script:
- echo Hello, %USERNAME%!
linux_job:
tags:
- linux
script:
- echo "Hello, $USER!"
GitHub 官方对照片段:
windows_job:
runs-on: windows-latest
steps:
- run: echo Hello, %USERNAME%!
linux_job:
runs-on: ubuntu-latest
steps:
- run: echo "Hello, $USER!"
这个 GitHub 片段必须放进 jobs。Windows 的 %USERNAME% 是 cmd 的变量写法,不能假定任意默认 shell 都会展开。下面显式选择 cmd;Linux 步骤显式使用 Bash:
jobs:
windows_job:
runs-on: windows-latest
steps:
- shell: cmd
run: echo Hello, %USERNAME%!
linux_job:
runs-on: ubuntu-latest
steps:
- shell: bash
run: echo "Hello, $USER!"
该修正仍是 jobs 配置片段,需与前述工作流触发器合并。详见 工作流语法。
Docker 镜像:image 与 container
GitLab 的 image 与 GitHub 的 container 指定任务执行使用的容器镜像。主机运行器与容器镜像是两个层次,容器不能代替 runs-on。
GitLab CI/CD 配置片段:
my_job:
image: node:20-bookworm-slim
GitHub Actions 配置片段:
jobs:
my_job:
container: node:20-bookworm-slim
两例都只展示镜像字段,需补上脚本或步骤。GitHub 容器任务还需选支持 Docker 的 Linux 运行器。镜像中的 Node 版本应由项目约束决定;node:20-bookworm-slim 是官方对照示例,不代表对当前所有项目的版本建议。详见 任务容器。
条件和表达式:rules 与 if
GitLab 用 rules 决定任务是否纳入流水线;GitHub 用任务或步骤的 if 决定是否执行。迁移时必须比较事件语义,而不仅是表达式长得相似。
GitLab CI/CD:
deploy_prod:
stage: deploy
script:
- echo "Deploy to production server"
rules:
- if: '$CI_COMMIT_BRANCH == "master"'
GitHub 官方对照片段:
jobs:
deploy_prod:
if: contains( github.ref, 'master')
runs-on: ubuntu-latest
steps:
- run: echo "Deploy to production server"
这里的官方片段不是精确等价映射:contains(github.ref, 'master') 是子串匹配,可能匹配 master-fix 或包含这个词的标签。若要求只在推送到名为 master 的分支时部署,应同时限定事件和完整分支引用:
jobs:
deploy_prod:
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
runs-on: ubuntu-latest
steps:
- run: echo "Deploy to production server"
上例还需要工作流级的 on: push 等触发配置;它是“只允许 master 分支推送”的示例,不能覆盖 GitLab 合并请求、定时或手动流水线的全部规则。若项目默认分支叫 main,应按真实需求改引用。详见 表达式。
任务依赖:stages 与 needs
GitLab 的同一阶段内任务可以并行,后续阶段默认等待前一阶段完成。GitHub 用 needs 显式声明任务依赖。下例先并行构建 A 与 B,再测试,最后部署:
GitLab CI/CD:
stages:
- build
- test
- deploy
build_a:
stage: build
script:
- echo "This job will run first."
build_b:
stage: build
script:
- echo "This job will run first, in parallel with build_a."
test_ab:
stage: test
script:
- echo "This job will run after build_a and build_b have finished."
deploy_ab:
stage: deploy
script:
- echo "This job will run after test_ab is complete"
GitHub Actions:
jobs:
build_a:
runs-on: ubuntu-latest
steps:
- run: echo "This job will be run first."
build_b:
runs-on: ubuntu-latest
steps:
- run: echo "This job will be run first, in parallel with build_a"
test_ab:
runs-on: ubuntu-latest
needs: [build_a,build_b]
steps:
- run: echo "This job will run after build_a and build_b have finished"
deploy_ab:
runs-on: ubuntu-latest
needs: [test_ab]
steps:
- run: echo "This job will run after test_ab is complete"
test_ab 等待两个构建任务,deploy_ab 等待测试任务。失败和跳过的依赖会影响后续任务是否执行;如项目要允许失败或总是清理,应另行设计 if,不能机械翻译。详见 needs。
定时执行
GitLab 在界面中配置流水线计划;GitHub 在 YAML 的 on.schedule 下配置计划。迁移时应同时核对时间表达式、实际时区、默认分支和触发身份,而不仅是复制时间字符串。GitHub 的定时工作流只在默认分支运行,也可能延迟;它不适合作为严格准点的保证。
具体配置以 触发工作流的事件:schedule 为准。本节没有替用户创建任何定时任务。
变量和秘密
两者均支持在配置文件内定义普通变量,并通过各自界面管理秘密。迁移时重新建立仓库或环境作用域的秘密,核对变量名、授权环境和访问条件。秘密的实际值不应放进 YAML、稿件或日志。普通变量与秘密不是同一个存储层,不能只替换字段名。
缓存
缓存适合保存可重新获取的依赖或构建中间结果。GitLab 在 cache 下定义路径和键;GitHub 使用缓存 Action。两边键的策略也要重新核对:分支标识与锁文件哈希并不等价。
GitLab CI/CD:
image: node:latest
cache:
key: $CI_COMMIT_REF_SLUG
paths:
- .npm/
before_script:
- npm ci --cache .npm --prefer-offline
test_async:
script:
- node ./specs/start.js ./specs/async.spec.js
GitHub 官方缓存片段:
jobs:
test_async:
runs-on: ubuntu-latest
steps:
- name: Cache node modules
uses: actions/cache@v4
with:
path: ~/.npm
key: v1-npm-deps-${{ hashFiles('**/package-lock.json') }}
restore-keys: v1-npm-deps-
该片段缓存的是 ~/.npm 下的 npm 缓存,并非安装后的 node_modules。它省略了检出、安装和测试步骤,单独使用不会执行测试。hashFiles 应在锁文件已经检出后计算。下面补齐步骤,并用 setup-node 的缓存能力表示同一目的;不要再为同一路径叠加一次 actions/cache:
jobs:
test_async:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: '20'
cache: npm
cache-dependency-path: package-lock.json
- run: npm ci
- run: node ./specs/start.js ./specs/async.spec.js
这个补充例子要求仓库已有匹配的 package.json、package-lock.json 和测试脚本。Node 主版本与 Action 主版本需按实际项目、运行器兼容性及组织策略核验;未声称此示例已运行。
构件
两种系统都能上传任务生成的文件或目录。GitHub 构件可在不同任务间持久保存和传递数据,但上传不会自动把文件放入另一个任务;后续任务还需下载相应构件。
GitLab 官方字段片段:
script:
artifacts:
paths:
- math-homework.txt
它没有任务名,且 script 为空,只展示 artifacts.paths 字段;不能直接当成有效完整流水线。
GitHub 官方上传步骤片段:
- name: Upload math result for job 1
uses: actions/upload-artifact@v4
with:
name: homework
path: math-homework.txt
把此步骤放在任务的 steps 下,并先生成 math-homework.txt。源例的 homework 是构件名称,path 才是要上传的文件路径。构件与缓存用途不同,不应用缓存代替应留存的交付物。详见 保存和共享数据。
数据库与服务容器
两种系统都可以启动数据库、缓存等附加服务。GitLab 与 GitHub 都用 services,但结构和网络环境不同;任务容器由前述 image 或 container 控制。
GitLab CI/CD:
container-job:
variables:
POSTGRES_PASSWORD: postgres
# The hostname used to communicate with the
# PostgreSQL service container
POSTGRES_HOST: postgres
# The default PostgreSQL port
POSTGRES_PORT: 5432
image: node:20-bookworm-slim
services:
- postgres
script:
# Performs a clean installation of all dependencies
# in the `package.json` file
- npm ci
# Runs a script that creates a PostgreSQL client,
# populates the client with data, and retrieves data
- node client.js
tags:
- docker
GitHub Actions:
jobs:
container-job:
runs-on: ubuntu-latest
container: node:20-bookworm-slim
services:
postgres:
image: postgres
env:
POSTGRES_PASSWORD: postgres
steps:
- name: Check out repository code
uses: actions/checkout@v6
# Performs a clean installation of all dependencies
# in the `package.json` file
- name: Install dependencies
run: npm ci
- name: Connect to PostgreSQL
# Runs a script that creates a PostgreSQL client,
# populates the client with data, and retrieves data
run: node client.js
env:
# The hostname used to communicate with the
# PostgreSQL service container
POSTGRES_HOST: postgres
# The default PostgreSQL port
POSTGRES_PORT: 5432
这里的任务本身在 Node 容器内,因此通过服务名 postgres 和容器端口 5432 访问数据库。若改为直接在运行器上运行,需核对端口映射和主机地址,不能沿用容器间网络假设。
POSTGRES_PASSWORD: postgres 是官方演示值,不是实际凭据,也不能直接用于公开或生产数据库。源码例子还没有定义数据库健康检查;真实任务应确认服务就绪,再运行客户端。两段示例要求仓库提供 client.js 与 npm 锁文件,不包含其实现,也没有证据证明已完成数据库联调。详见 Docker 服务容器。
迁移时的核对顺序
先列出原流水线的事件和分支规则,再确认每个任务的运行器、shell、镜像和依赖。随后迁移缓存与构件,建立秘密,最后用项目真实输入核验部署权限、失败路径和数据库启动顺序。官方片段用于说明字段,不能代替完整工作流的验证。
来源与许可
原文:GitHub 文档:从 GitLab CI/CD 迁移到 GitHub Actions。作者及版权:GitHub 文档团队 / GitHub。文档正文依 CC BY 4.0 使用,参见 许可条款。
本文覆盖原文所有章节和 16 个代码片段;调整静态格式,补充片段边界、完整任务样例,明确修正分支子串匹配与 Windows shell 假设,未执行代码。修改日期:2026-10-03。本文改编正文同以 CC BY 4.0 提供。
源代码依 GitHub 文档代码 MIT 许可 使用。以下保留许可声明:
MIT License
Copyright 2026 GitHub
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.











暂无评论内容