1. 概述

在 GitLab CI 流水线中实现向代码仓库推送变更的能力,可以有效自动化一些场景,例如版本号更新、依赖项升级等。这不仅能减少手动操作,还能提升流程的一致性和可重复性。

本文将介绍几种在 GitLab CI 中实现推送变更的常见认证方式,并附上具体示例代码和配置说明。


2. 使用访问令牌(Access Token)

这是最常见也最简单的一种方式,适用于大多数项目自动化场景。

2.1 配置步骤

GitLab 支持多种访问令牌类型,包括:

  • 个人访问令牌(Personal Access Token)
  • 项目访问令牌(Project Access Token)
  • 群组访问令牌(Group Access Token)

根据你的权限需求选择合适的类型。以个人访问令牌为例,创建一个名为 AUTOMATION_ACCESS_TOKEN 的令牌,并赋予 write_repository 权限:

GitLab Personal Access Token

创建完成后,在项目的 CI/CD 设置中添加一个变量:

GitLab CICD Variable Access Token

2.2 示例配置

将以下内容添加到 .gitlab-ci.yml 文件中:

push_changes:
  image: ubuntu:latest
  before_script: |
    apt-get update && apt-get install -y git >/dev/null
    git config --global user.email ${GITLAB_USER_EMAIL}
    git config --global user.name ${GITLAB_USER_NAME}
    git remote set-url origin https://oauth2:${AUTOMATION_ACCESS_TOKEN}@${CI_PROJECT_URL#https://}.git
  script: |
    git commit -m "noop" --allow-empty
    git push origin -o ci.skip HEAD:main

📌 说明:

  • git remote set-url 设置了使用 token 的认证方式。
  • git push 使用了 -o ci.skip 参数来避免触发新的流水线,防止无限循环。
  • --allow-empty 允许提交空变更。

2.3 实际运行效果

GitLab CI/CD - Push Changes Job with Access Token

✅ 优点:配置简单,适合快速集成
❌ 缺点:token 管理需谨慎,权限控制不够细粒度


3. 使用 SSH 密钥

使用 SSH 密钥推送代码,适合需要更高安全性和权限控制的场景。

3.1 配置步骤

首先,生成一对 SSH 密钥:

ssh-keygen -t rsa -b 4096 -C "[email protected]"

将公钥添加到 GitLab 用户设置中:

GitLab CI/CD - Add SSH Public Key

然后,将私钥进行 Base64 编码,并添加为 CI/CD 变量 SSH_PRIVATE_KEY_BASE64

cat ~/.ssh/id_rsa | base64

GitLab CI/CD - SSH Private Key Variable

3.2 示例配置

push_changes:
  image: ubuntu:latest
  before_script: |
    apt-get update && apt-get install -y openssh-client git >/dev/null
    mkdir -p ~/.ssh && chmod 700 ~/.ssh
    echo -n "$SSH_PRIVATE_KEY_BASE64" | base64 -d > ~/.ssh/ssh_private_key
    cat << EOF >> ~/.ssh/config
    Host gitlab.com
        User git
        IdentityFile ~/.ssh/ssh_private_key
        IdentitiesOnly yes
    StrictHostKeyChecking no
    EOF
    chmod -R 400 ~/.ssh/ssh_private_key ~/.ssh/config
    git config --global user.email ${GITLAB_USER_EMAIL}
    git config --global user.name ${GITLAB_USER_NAME}
    eval "$(ssh-agent -s)"
    ssh-add ~/.ssh/ssh_private_key
    git remote set-url origin [email protected]:${CI_PROJECT_PATH}.git
  script: |
    git commit -m "noop" --allow-empty
    git push origin -o ci.skip HEAD:main

📌 说明:

  • 使用了 ssh-agent 管理私钥。
  • 通过 StrictHostKeyChecking no 跳过首次连接确认,避免流水线阻塞。
  • 同样使用了 -o ci.skip 避免触发新流水线。

3.3 实际运行效果

GitLab CI/CD - Push Changes Job with SSH Keys

✅ 优点:更安全,适合权限控制严格场景
❌ 缺点:配置步骤较多,维护成本略高


4. 使用 GitLab API 推送变更

除了使用 Git 协议,也可以通过 GitLab 提供的 Commit API 来直接推送变更。

4.1 示例配置

push_changes:
  image: curlimages/curl:latest
  rules:
    - if: '$CI_COMMIT_MESSAGE !~ /noop/'
  variables:
    FILE_PATH: README.md
    COMMIT_MESSAGE: noop
    API_URL: "https://gitlab.com/api/v4/projects/$CI_PROJECT_ID/repository/commits"
  before_script: |
    FILE_CONTENT=$(curl --header "PRIVATE-TOKEN: $AUTOMATION_ACCESS_TOKEN" \
      "https://gitlab.com/api/v4/projects/$CI_PROJECT_ID/repository/files/$FILE_PATH/raw?ref=$CI_COMMIT_REF_NAME" | base64)
  script: |
    curl --request POST "$API_URL" \
      --header "PRIVATE-TOKEN: $AUTOMATION_ACCESS_TOKEN" \
      --header "Content-Type: application/json" \
      --data '{
        "branch": "'$CI_COMMIT_REF_NAME'", 
        "commit_message": "'$COMMIT_MESSAGE'",
        "actions": [{"action": "update", "file_path": "'$FILE_PATH'", "content": "'$FILE_CONTENT'", "encoding": "base64"}]
      }'

📌 说明:

  • 通过 API 获取文件内容并重新提交,模拟一次“noop”提交。
  • 使用 rules 条件防止无限流水线循环。

4.2 实际运行效果

GitLab CI/CD - Push Changes Job with GitLab API

✅ 优点:无需 clone 仓库,适合轻量级操作
❌ 缺点:API 调用较复杂,对文件内容处理有局限性


5. 总结

方式 适用场景 安全性 易用性 推荐指数
访问令牌(Access Token) 快速集成、小项目 ⭐⭐⭐⭐
SSH 密钥 权限控制严格、中大型项目 ⭐⭐⭐⭐⭐
GitLab API 无需 clone 仓库的轻量级操作 ⭐⭐⭐

📌 踩坑提醒:

  • 不要忘记使用 -o ci.skip 避免无限流水线
  • 私钥 Base64 编码时注意格式和换行问题
  • Token 和 SSH 密钥都应设置合理的过期时间

通过本文介绍的几种方式,你可以根据项目规模和安全需求,灵活选择最适合的推送方式。


原始标题:How to Push Changes to a Repository from a GitLab CI Pipeline