说明:本文档涵盖 GitLab 社区版(CE)和企业版(EE)的 REST API 与 GraphQL API 核心用法,适用于日常运维、CI/CD 集成、自动化脚本开发等场景。
GitLab 提供两个主要 API:
| API 类型 | 端点 | 适用场景 |
|---|---|---|
| REST API v4 | https://gitlab.example.com/api/v4 |
通用操作、脚本集成、第三方工具 |
| GraphQL API | https://gitlab.example.com/api/graphql |
复杂查询、前端集成、减少请求次数 |
重要约定:
per_page=100 参数)v4 已稳定多年,GitLab 承诺向后兼容GET /api/v4/projects # 列出项目
POST /api/v4/projects # 创建项目
GET /api/v4/projects/:id # 获取项目详情
PUT /api/v4/projects/:id # 更新项目
DELETE /api/v4/projects/:id # 删除项目
{
"id": 123,
"name": "my-project",
"path": "my-project",
"web_url": "https://gitlab.example.com/group/my-project",
"created_at": "2024-01-15T08:30:00Z",
"last_activity_at": "2024-06-20T14:22:00Z"
}
GitLab 使用 Link Header 进行分页:
# 获取第 2 页,每页 50 条
curl --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.example.com/api/v4/projects?page=2&per_page=50"
响应头中的 Link 字段包含:
<...>; rel="next" — 下一页<...>; rel="prev" — 上一页<...>; rel="first" — 第一页<...>; rel="last" — 最后一页创建方式:
api, read_repository, write_repository)使用方式:
# 方式一:Header 传递
curl --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.example.com/api/v4/projects"
# 方式二:Query 参数(不推荐,Token 可能泄露到日志)
curl "https://gitlab.example.com/api/v4/projects?private_token=<TOKEN>"
常用 Scope 说明:
| Scope | 权限 |
|---|---|
api |
完整 API 读写权限 |
read_api |
只读 API 权限 |
read_repository |
读取代码仓库 |
write_repository |
写入代码仓库 |
read_user |
读取用户信息 |
sudo |
以其他用户身份执行操作(管理员) |
适用于第三方应用集成:
1. 注册应用获取 Client ID / Secret
2. 引导用户授权获取 Authorization Code
3. 用 Code 换取 Access Token
4. 使用 Access Token 调用 API
在 GitLab CI/CD Pipeline 中,自动注入 CI_JOB_TOKEN:
# .gitlab-ci.yml
stages:
- deploy
deploy:
stage: deploy
script:
- curl --header "JOB-TOKEN: $CI_JOB_TOKEN" \
"https://gitlab.example.com/api/v4/projects/$CI_PROJECT_ID/repository/tags"
Job Token 权限限制:
| 方式 | 适用场景 | 安全性 | 有效期 |
|---|---|---|---|
| Personal Token | 个人脚本、自动化工具 | 中(需妥善保管) | 可配置(建议 90 天内) |
| OAuth 2.0 | 第三方应用 | 高 | 短期 + Refresh Token |
| Job Token | CI/CD Pipeline | 高 | Pipeline 运行期间 |
| Deploy Token | 外部系统拉取代码 | 高 | 长期固定 |
# 列出自己有权限的所有项目
curl --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.example.com/api/v4/projects?per_page=100" | jq
# 列出特定群组的项目
curl --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.example.com/api/v4/groups/:group_id/projects" | jq
# 搜索项目
curl --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.example.com/api/v4/projects?search=my-project" | jq
# 创建个人项目
curl --request POST --header "PRIVATE-TOKEN: <TOKEN>" \
--header "Content-Type: application/json" \
--data '{
"name": "new-project",
"description": "项目描述",
"visibility": "private",
"initialize_with_readme": true
}' \
"https://gitlab.example.com/api/v4/projects"
# 在指定群组下创建项目
curl --request POST --header "PRIVATE-TOKEN: <TOKEN>" \
--header "Content-Type: application/json" \
--data '{
"name": "group-project",
"namespace_id": 42,
"visibility": "internal"
}' \
"https://gitlab.example.com/api/v4/projects"
visibility 选项:
private — 仅成员可见internal — 登录用户可见public — 完全公开# 获取项目详情
curl --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.example.com/api/v4/projects/:id" | jq
# 更新项目设置
curl --request PUT --header "PRIVATE-TOKEN: <TOKEN>" \
--header "Content-Type: application/json" \
--data '{
"description": "更新后的描述",
"visibility": "internal",
"default_branch": "main"
}' \
"https://gitlab.example.com/api/v4/projects/:id"
# 删除项目(⚠️ 不可逆)
curl --request DELETE --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.example.com/api/v4/projects/:id"
# 列出项目成员
curl --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.example.com/api/v4/projects/:id/members" | jq
# 添加成员
curl --request POST --header "PRIVATE-TOKEN: <TOKEN>" \
--header "Content-Type: application/json" \
--data '{
"user_id": 5,
"access_level": 30
}' \
"https://gitlab.example.com/api/v4/projects/:id/members"
Access Level 常量:
| 值 | 角色 | 权限 |
|---|---|---|
| 10 | Guest | 创建 Issue、发表评论 |
| 20 | Reporter | 查看代码、创建分支 |
| 30 | Developer | 推送代码、合并请求 |
| 40 | Maintainer | 管理项目设置、成员 |
| 50 | Owner | 完全控制(仅群组 Owner) |
# 列出所有可见群组
curl --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.example.com/api/v4/groups?per_page=100" | jq
# 获取群组详情
curl --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.example.com/api/v4/groups/:group_id" | jq
# 创建子群组
curl --request POST --header "PRIVATE-TOKEN: <TOKEN>" \
--header "Content-Type: application/json" \
--data '{
"name": "sub-group",
"path": "sub-group",
"parent_id": 42
}' \
"https://gitlab.example.com/api/v4/groups"
原始核心命令保留 — 这是 Hugo 日常最常用的操作之一
# 列出一个组内所有的代码地址(不包含子组)
curl --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.awx.im/api/v4/groups/gtpn" | \
jq '.projects[] | .http_url_to_repo'
# 当需要包括子组内的代码时
curl --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.awx.im/api/v4/groups/financial_platform/projects?include_subgroups=true" | \
jq '.[] | .http_url_to_repo'
关键参数说明:
| 参数 | 说明 | 默认值 |
|---|---|---|
include_subgroups |
是否包含子群组项目 | false |
per_page |
每页数量 | 20 |
page |
页码 | 1 |
archived |
是否包含归档项目 | false |
simple |
简化响应(仅基本字段) | false |
完整版:导出所有仓库地址到文件:
#!/bin/bash
# export-repos.sh - 导出群组内所有仓库地址
GROUP_ID="financial_platform"
TOKEN="<YOUR_TOKEN>"
GITLAB_URL="https://gitlab.awx.im"
OUTPUT_FILE="repos.txt"
# 清空输出文件
> "$OUTPUT_FILE"
# 分页获取所有项目
page=1
while true; do
response=$(curl -s --header "PRIVATE-TOKEN: $TOKEN" \
"${GITLAB_URL}/api/v4/groups/${GROUP_ID}/projects?include_subgroups=true&per_page=100&page=${page}")
# 检查是否为空
if [ "$(echo "$response" | jq 'length')" -eq 0 ]; then
break
fi
# 提取仓库地址
echo "$response" | jq -r '.[] | .http_url_to_repo' >> "$OUTPUT_FILE"
page=$((page + 1))
done
echo "导出完成,共 $(wc -l < "$OUTPUT_FILE") 个仓库"
# 获取仓库文件内容
curl --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.example.com/api/v4/projects/:id/repository/files/README.md/raw?ref=main"
# 获取文件信息(包含提交历史)
curl --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.example.com/api/v4/projects/:id/repository/files/README.md?ref=main" | jq
# 创建新文件
curl --request POST --header "PRIVATE-TOKEN: <TOKEN>" \
--header "Content-Type: application/json" \
--data '{
"branch": "main",
"content": "SGVsbG8gV29ybGQh", # Base64 编码
"commit_message": "Add new file",
"encoding": "base64"
}' \
"https://gitlab.example.com/api/v4/projects/:id/repository/files/new-file.txt"
# 更新文件
curl --request PUT --header "PRIVATE-TOKEN: <TOKEN>" \
--header "Content-Type: application/json" \
--data '{
"branch": "main",
"content": "VXBkYXRlZCBjb250ZW50", # Base64 编码
"commit_message": "Update file"
}' \
"https://gitlab.example.com/api/v4/projects/:id/repository/files/README.md"
# 列出分支
curl --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.example.com/api/v4/projects/:id/repository/branches" | jq
# 创建分支
curl --request POST --header "PRIVATE-TOKEN: <TOKEN>" \
--header "Content-Type: application/json" \
--data '{
"branch": "feature/new-feature",
"ref": "main"
}' \
"https://gitlab.example.com/api/v4/projects/:id/repository/branches"
# 保护分支
curl --request PUT --header "PRIVATE-TOKEN: <TOKEN>" \
--header "Content-Type: application/json" \
--data '{
"allow_force_push": false,
"code_owner_approval_required": true
}' \
"https://gitlab.example.com/api/v4/projects/:id/protected_branches/main"
# 删除分支
curl --request DELETE --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.example.com/api/v4/projects/:id/repository/branches/feature/old-branch"
# 列出项目的 Pipeline
curl --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.example.com/api/v4/projects/:id/pipelines" | jq
# 获取特定 Pipeline 详情
curl --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.example.com/api/v4/projects/:id/pipelines/:pipeline_id" | jq
# 创建新 Pipeline
curl --request POST --header "PRIVATE-TOKEN: <TOKEN>" \
--header "Content-Type: application/json" \
--data '{
"ref": "main",
"variables": [
{"key": "DEPLOY_ENV", "value": "staging"}
]
}' \
"https://gitlab.example.com/api/v4/projects/:id/pipeline"
# 重试失败的 Pipeline
curl --request POST --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.example.com/api/v4/projects/:id/pipelines/:pipeline_id/retry"
# 取消 Pipeline
curl --request POST --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.example.com/api/v4/projects/:id/pipelines/:pipeline_id/cancel"
| 状态 | 说明 |
|---|---|
created |
已创建,等待运行 |
waiting_for_resource |
等待可用资源 |
preparing |
准备中 |
pending |
排队中 |
running |
运行中 |
success |
成功 |
failed |
失败 |
canceled |
已取消 |
skipped |
已跳过 |
manual |
等待手动触发 |
# 列出 Pipeline 中的 Jobs
curl --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.example.com/api/v4/projects/:id/pipelines/:pipeline_id/jobs" | jq
# 获取 Job 日志
curl --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.example.com/api/v4/projects/:id/jobs/:job_id/trace"
# 重试特定 Job
curl --request POST --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.example.com/api/v4/projects/:id/jobs/:job_id/retry"
# 创建触发器
curl --request POST --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.example.com/api/v4/projects/:id/triggers" | jq
# 使用触发器 Token 触发 Pipeline
curl --request POST \
--form "token=TRIGGER_TOKEN" \
--form "ref=main" \
--form "variables[DEPLOY_ENV]=production" \
"https://gitlab.example.com/api/v4/projects/:id/trigger/pipeline"
# 列出所有用户(管理员权限)
curl --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.example.com/api/v4/users?per_page=100" | jq
# 搜索用户
curl --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.example.com/api/v4/users?search=zhangsan" | jq
# 获取当前用户信息
curl --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.example.com/api/v4/user" | jq
# 列出群组成员
curl --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.example.com/api/v4/groups/:group_id/members" | jq
# 添加群组成员
curl --request POST --header "PRIVATE-TOKEN: <TOKEN>" \
--header "Content-Type: application/json" \
--data '{
"user_id": 5,
"access_level": 30,
"expires_at": "2024-12-31"
}' \
"https://gitlab.example.com/api/v4/groups/:group_id/members"
# 更新成员权限
curl --request PUT --header "PRIVATE-TOKEN: <TOKEN>" \
--header "Content-Type: application/json" \
--data '{
"access_level": 40,
"expires_at": "2025-06-30"
}' \
"https://gitlab.example.com/api/v4/groups/:group_id/members/:user_id"
# 移除成员
curl --request DELETE --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.example.com/api/v4/groups/:group_id/members/:user_id"
# 列出当前用户的 SSH 密钥
curl --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.example.com/api/v4/user/keys" | jq
# 添加 SSH 密钥
curl --request POST --header "PRIVATE-TOKEN: <TOKEN>" \
--header "Content-Type: application/json" \
--data '{
"title": "My MacBook Pro",
"key": "ssh-rsa AAAA..."
}' \
"https://gitlab.example.com/api/v4/user/keys"
# 列出项目 Issue
curl --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.example.com/api/v4/projects/:id/issues?state=opened" | jq
# 创建 Issue
curl --request POST --header "PRIVATE-TOKEN: <TOKEN>" \
--header "Content-Type: application/json" \
--data '{
"title": "Bug: 登录失败",
"description": "## 问题描述\n\n登录时返回 500 错误...",
"labels": "bug,high-priority",
"assignee_ids": [5]
}' \
"https://gitlab.example.com/api/v4/projects/:id/issues"
# 更新 Issue
curl --request PUT --header "PRIVATE-TOKEN: <TOKEN>" \
--header "Content-Type: application/json" \
--data '{
"state_event": "close",
"labels": "bug,resolved"
}' \
"https://gitlab.example.com/api/v4/projects/:id/issues/:issue_iid"
# 列出项目 MR
curl --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.example.com/api/v4/projects/:id/merge_requests?state=opened" | jq
# 创建 MR
curl --request POST --header "PRIVATE-TOKEN: <TOKEN>" \
--header "Content-Type: application/json" \
--data '{
"source_branch": "feature/new-feature",
"target_branch": "main",
"title": "feat: 新增用户管理功能",
"description": "## 变更内容\n\n- 新增用户 CRUD\n- 添加权限校验",
"remove_source_branch": true
}' \
"https://gitlab.example.com/api/v4/projects/:id/merge_requests"
# 合并 MR
curl --request PUT --header "PRIVATE-TOKEN: <TOKEN>" \
--header "Content-Type: application/json" \
--data '{
"squash": true,
"squash_commit_message": "feat: 新增用户管理功能"
}' \
"https://gitlab.example.com/api/v4/projects/:id/merge_requests/:merge_request_iid/merge"
# 获取 MR 的 Diff
curl --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.example.com/api/v4/projects/:id/merge_requests/:merge_request_iid/diffs" | jq
# 添加评论
curl --request POST --header "PRIVATE-TOKEN: <TOKEN>" \
--header "Content-Type: application/json" \
--data '{
"body": "这里建议添加异常处理",
"position": {
"base_sha": "abc123",
"head_sha": "def456",
"start_sha": "abc123",
"position_type": "text",
"new_path": "src/main.py",
"new_line": 42
}
}' \
"https://gitlab.example.com/api/v4/projects/:id/merge_requests/:merge_request_iid/discussions"
| 特性 | REST API | GraphQL API |
|---|---|---|
| 数据获取 | 固定端点,可能过度获取 | 精确获取所需字段 |
| 请求次数 | 多次请求获取关联数据 | 单次请求获取嵌套数据 |
| 复杂度 | 简单直观 | 学习曲线较陡 |
| 适用场景 | 简单 CRUD | 复杂查询、前端集成 |
# 查询项目基本信息
query {
project(fullPath: "group/project") {
id
name
description
starCount
forkCount
repository {
tree {
blobs {
nodes {
name
path
}
}
}
}
}
}
# GraphQL 查询
curl --request POST \
--header "PRIVATE-TOKEN: <TOKEN>" \
--header "Content-Type: application/json" \
--data '{
"query": "query { project(fullPath: \"group/project\") { name description } }"
}' \
"https://gitlab.example.com/api/graphql"
问题:401 Unauthorized
排查步骤:
PRIVATE-TOKEN 或 Authorization: Bearer)# 验证 Token 有效性
curl --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.example.com/api/v4/user" | jq
问题:只获取到前 20 条记录
原因:GitLab 默认分页为 20 条
解决:
# 增加 per_page 参数(最大 100)
curl --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.example.com/api/v4/projects?per_page=100"
# 或使用分页循环获取全部数据
问题:群组 API 返回的项目数量少于预期
原因:未包含子群组项目
解决:
# 添加 include_subgroups=true 参数
curl --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.example.com/api/v4/groups/:id/projects?include_subgroups=true"
问题:项目名或路径包含中文、空格时 API 调用失败
解决:
# 对路径进行 URL 编码
# 例如:"我的项目" → "%E6%88%91%E7%9A%84%E9%A1%B9%E7%9B%AE"
curl --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.example.com/api/v4/projects/$(python3 -c "import urllib.parse; print(urllib.parse.quote('我的项目'))")"
问题:频繁请求导致 429 Too Many Requests
GitLab 默认限制:
应对策略:
per_page=100 减少请求次数问题:不确定使用数字 ID 还是路径
说明:
:id 可以是数字 ID 或 URL 编码的路径(如 group%2Fproject)group/project → URL 编码为 group%2Fproject# 使用路径(需要 URL 编码)
curl --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.example.com/api/v4/projects/group%2Fproject"
# 使用数字 ID(推荐)
curl --header "PRIVATE-TOKEN: <TOKEN>" \
"https://gitlab.example.com/api/v4/projects/42"
| 工具 | 用途 |
|---|---|
jq |
JSON 解析与格式化 |
curl |
HTTP 请求 |
httpie |
更友好的 HTTP 客户端 |
| Postman | API 调试与测试 |
https://gitlab.awx.im{部门}/{项目} 或 {部门}/{子组}/{项目}~/scripts/gitlab-export/文档信息
- 原始内容:GitLab API 基础命令(356 字)
- 优化后字数:约 12,000 字
- 覆盖范围:REST API、GraphQL、认证、项目管理、群组管理、CI/CD、权限管理、Issue/MR、踩坑记录
- 保留原始命令:群组仓库导出
curl + jq命令原样保留