作者:没有四次元口袋的蓝胖
日期:2026-10-08
标签:GitLab, CI/CD, 团队协作
GitLab知识梳理
写在前面
上一篇我们搞定了 Git 的核心操作------从三区模型到分支管理,算是把"单机版"的 Git 玩明白了。但实际工作中,没有人靠命令行邮件互发 patch 来协作。我们需要一个中心化的平台来托管代码、管理协作、跑自动化流程。
GitLab 就是这样一种平台------它提供了代码托管、Issue 跟踪、CI/CD 流水线、代码 Review 等一整套 DevOps 能力。很多公司用 GitLab 作为内部代码仓库,配合 CI/CD 实现从代码提交到自动部署的全链路自动化。
本文覆盖:GitLab 基本使用、MR 合并请求流程、代码 Review 规范、团队协作分支策略,以及 GitLab CI/CD 入门。
一、GitLab 是什么?
1.1 代码托管平台对比
| 特性 | GitHub | GitLab | Gitee |
|---|---|---|---|
| 定位 | 开源社区为主 | 企业 DevOps 平台 | 国内代码托管 |
| CI/CD | GitHub Actions | GitLab CI(内置,功能强大) | Gitee Go |
| 私有仓库 | 免费(有限制) | 免费(无限私有) | 免费 |
| 自部署 | 有 CE/EE 版本 | 有 CE/EE 版本 | 无 |
| 特色 | 开源生态最大 | DevOps 全流程一体化 | 国内访问快 |
为什么企业偏爱 GitLab?
- CI/CD 内置 :不需要额外配置,
.gitlab-ci.yml写进仓库就能跑 - 可私有部署:企业可以把 GitLab 部署在自己的服务器上,代码不出内网
- 权限体系完善:Group → Project → Branch 多层级权限控制
- DevOps 全链路:从代码管理到 CI/CD 到容器镜像仓库到监控,一站式
1.2 GitLab 的核心概念
| 概念 | 说明 |
|---|---|
| Group | 组织/团队,类似 GitHub 的 Organization |
| Project | 项目仓库,一个 Git 仓库 |
| Member | 成员,有 Guest/Reporter/Developer/Maintainer/Owner 五种角色 |
| Branch | 分支,受保护分支可以限制谁能 push |
| Merge Request (MR) | 合并请求,相当于 GitHub 的 Pull Request (PR) |
| Pipeline | CI/CD 流水线,一次自动化执行的完整流程 |
| Runner | 执行 Pipeline 的机器 |
二、GitLab 项目托管
2.1 创建项目
方式一:在 GitLab 上新建
- 登录 GitLab → 点击 "New Project"
- 选择 "Create blank project"(或从模板/导入已有仓库)
- 填写项目名称、可见性(Private/Internal/Public)
- 点击 "Create project"
方式二:把本地项目推送到 GitLab
bash
# 本地项目已有代码
cd my-project
git init
git add .
git commit -m "init: 项目初始化"
# 关联远程仓库
git remote add origin https://gitlab.company.com/group/project.git
# 推送并设置上游分支
git push -u origin main
2.2 SSH Key 配置
日常开发不建议每次 push 都输密码,配置 SSH Key 更方便:
bash
# 1. 生成 SSH 密钥对
ssh-keygen -t ed25519 -C "your@email.com"
# 2. 查看公钥内容
cat ~/.ssh/id_ed25519.pub
# 3. 复制公钥到 GitLab
# GitLab → Settings → SSH Keys → 粘贴公钥 → Add Key
# 4. 测试连接
ssh -T git@gitlab.company.com
# 看到 "Welcome to GitLab, @yourname!" 就成功了
# 5. 切换远程地址为 SSH 格式
git remote set-url origin git@gitlab.company.com:group/project.git
⚠️ 常见坑点 :如果公司有多个 GitLab 实例或多个账号,需要在
~/.ssh/config中配置不同的 Host 对应不同的密钥文件,否则会认证失败。
2.3 分支保护策略
生产分支(如 main、release/*)通常会设置保护,防止直接 push:
GitLab → Settings → Repository → Protected Branches
| 配置项 | 推荐设置 |
|---|---|
| Allowed to merge | Maintainers(或 Developers + Maintainers) |
| Allowed to push | No one(必须通过 MR) |
| Force push | Not allowed |
| Allowed to delete | Not allowed |
🎯 团队规范要求:所有代码变更必须通过 MR 合并,禁止直接 push 到 main 分支。这是业界最佳实践,也是你简历上可以写的团队协作规范。
三、MR 合并请求流程(核心工作流)
MR(Merge Request)是 GitLab 协作的核心机制。每一次代码变更都应该通过 MR 来合并。
3.1 完整的 MR 工作流
1. 从 main 创建 feature 分支
↓
2. 在 feature 分支上开发、提交
↓
3. push feature 分支到远程
↓
4. 在 GitLab 上创建 MR(feature → main)
↓
5. 指定 Reviewer 进行代码审查
↓
6. CI/CD Pipeline 自动跑测试
↓
7. Reviewer 提出修改意见 → 开发者修改 → 再次 push
↓
8. Reviewer Approve + Pipeline 通过
↓
9. 合并 MR(可选:Squash / Delete source branch)
3.2 创建 MR 的实操步骤
bash
# 1. 创建 feature 分支
git checkout main
git pull origin main # 先拉最新代码
git checkout -b feature/user-login
# 2. 开发并提交
# ... 写代码 ...
git add .
git commit -m "feat: 实现用户登录接口"
git commit -m "feat: 添加JWT鉴权"
# 3. 推送到远程
git push -u origin feature/user-login
推送完成后,GitLab 会在终端返回一个创建 MR 的链接。也可以手动在 GitLab 页面创建。
创建 MR 时需要填写的内容:
| 字段 | 说明 | 建议 |
|---|---|---|
| Title | MR 标题 | 简洁描述做了什么,如 feat: 实现用户登录接口 |
| Description | 详细描述 | 改了什么、为什么这么改、影响范围 |
| Assignee | 指派人 | 谁负责合并 |
| Reviewer | 审查人 | 谁来 Review 代码 |
| Labels | 标签 | feature / bugfix / hotfix 等 |
| Milestone | 里程碑 | 关联到哪个版本迭代 |
| Source branch | 源分支 | feature/user-login |
| Target branch | 目标分支 | main |
3.3 MR 的合并策略
GitLab 支持多种合并方式:
| 策略 | 说明 | 适用场景 |
|---|---|---|
| Merge commit | 创建 merge commit,保留分支历史 | 默认策略,适合大多数场景 |
| Squash and merge | 把 feature 的所有提交压缩成一个 | feature 有很多细碎提交时,保持 main 整洁 |
| Rebase and merge | 把 feature 提交 rebase 到 main 上 | 喜欢线性历史 |
| Fast-forward merge | 无 merge commit,直接移动指针 | 要求严格线性历史时 |
推荐实践:
- 功能开发用 Squash and merge(一个功能 = main 上一个干净的提交)
- 紧急修复用 Merge commit(保留完整的修复记录便于回溯)
3.4 MR 模板
团队可以创建 MR 模板,统一提交规范:
文件路径:.gitlab/merge_request_templates/Default.md
markdown
## 变更内容
<!-- 简要描述这个 MR 做了什么 -->
## 变更类型
- [ ] 新功能 (feat)
- [ ] Bug 修复 (fix)
- [ ] 重构 (refactor)
- [ ] 文档 (docs)
- [ ] 其他
## 影响范围
<!-- 列出受影响的模块或接口 -->
## 测试情况
- [ ] 本地测试通过
- [ ] 单元测试通过
- [ ] 无破坏性变更
## 截图/日志
<!-- 如有 UI 变更或关键日志,粘贴在这里 -->
## Checklist
- [ ] 代码已自测
- [ ] 已添加必要的注释
- [ ] 无硬编码的配置
- [ ] 敏感信息已脱敏
四、代码 Review
4.1 Review 的重要性
Code Review 不是走形式,它是保障代码质量最有效的低成本手段:
| 收益 | 说明 |
|---|---|
| 发现 Bug | 多一双眼睛看代码,很多低级错误当场就能发现 |
| 知识共享 | 团队成员互相了解对方负责的模块 |
| 统一规范 | 代码风格、架构决策在 Review 中逐渐统一 |
| 提升能力 | 新人通过 Review 学习资深开发者的思维方式 |
4.2 Reviewer 怎么 Review
Review 关注点(优先级从高到低):
- 逻辑正确性:业务逻辑对不对?边界条件处理了吗?
- 安全性:有没有 SQL 注入?XSS?敏感信息硬编码?
- 性能:有没有 N+1 查询?大循环里的重复计算?
- 可维护性:命名清晰吗?逻辑分层合理吗?
- 测试覆盖:关键路径有单元测试吗?
- 代码风格:格式、缩进、命名规范(这部分可以交给 lint 工具)
Review 评论规范:
🔴 [必须修改] 这里的 SQL 拼接存在注入风险,请改用 PreparedStatement
🟡 [建议优化] 这个循环可以提取成一个方法,提升可读性
🟢 [讨论] 这里用 HashMap 还是 TreeMap?当前场景下性能差异可以接受吗?
💡 [Nitpick] 变量名 `data` 太笼统,建议改为 `userLoginResponse`
4.3 GitLab 的 Review 功能
- 行级评论:直接在某一行代码上评论
- 讨论串:评论可以回复、解决(Resolve)
- Approve 机制:Reviewer 点 "Approve" 后才允许合并
- Code Owners :可以为特定目录指定固定 Reviewer(如
*.sql文件必须 DBA Review)
CODEOWNERS 文件示例(.gitlab/CODEOWNERS):
# 默认 Reviewer
* @team-lead
# 前端代码
/src/frontend/ @frontend-team
# 数据库相关
/db/migration/ @dba-team @team-lead
# 安全敏感配置
/src/main/resources/application*.yml @security-team
五、团队协作分支策略
5.1 常见的分支模型
Git Flow(经典,适合有版本发布节奏的项目)
main ●──────────────────────●──── 生产环境
↗ ↗
develop ●──●──●──●──●──●──●──●──●── 开发主线
↗ ↗
feature/a ●──●──● 功能分支
↗
feature/b ●──●──● 功能分支
release/1.0 ●──●──● 发布准备分支
hotfix ●──● 紧急修复分支
| 分支 | 用途 | 生命周期 |
|---|---|---|
main |
生产环境代码,每个 commit 对应一个版本 | 永久 |
develop |
开发主线,集成所有已完成的功能 | 永久 |
feature/* |
新功能开发 | 完成后合入 develop,删除 |
release/* |
版本发布前的准备(修 Bug、改文档) | 发布后合入 main + develop,删除 |
hotfix/* |
生产紧急修复 | 修复后合入 main + develop,删除 |
GitHub Flow(简化版,适合持续部署的项目)
main ●──●──●──────●──●──────●── 生产环境(始终可部署)
↗ ↗ ↗
feature ●──●──● ●──●──● ●──● 功能分支(短命)
规则更简单:
main始终是生产就绪的- 从
main创建 feature 分支 - 开发完成后提 MR,Review + CI 通过后合并
- 合并即部署
5.2 你团队的工作流(MR 驱动)
根据团队要求"所有 push 走 MR,CI/CD 跑通才允许合并",实际工作流是:
1. 从 main 拉出 feature/xxx 或 bugfix/xxx 分支
↓
2. 本地开发,多次 commit(粒度可以细一些)
↓
3. push 到远程(推送到自己的 feature 分支)
↓
4. 在 GitLab 创建 MR → main
↓
5. CI/CD Pipeline 自动触发
├── 编译检查
├── 单元测试
├── 代码质量检查(SonarQube 等)
└── 安全扫描
↓
6. Pipeline 全部通过 ✅
↓
7. Reviewer 审查代码,提出修改意见
↓
8. 开发者修改后 push(MR 自动更新)
↓
9. Reviewer Approve ✅
↓
10. 合并 MR(CI/CD 可能再次触发 → 自动部署)
5.3 分支命名规范
| 类型 | 命名格式 | 示例 |
|---|---|---|
| 功能 | feature/简短描述 |
feature/user-login |
| 修复 | bugfix/issue编号-描述 |
bugfix/123-null-pointer |
| 热修复 | hotfix/issue编号-描述 |
hotfix/456-login-crash |
| 发布 | release/版本号 |
release/v1.2.0 |
六、GitLab CI/CD 入门
6.1 什么是 CI/CD?
| 概念 | 全称 | 含义 |
|---|---|---|
| CI | Continuous Integration(持续集成) | 频繁地将代码集成到主干,每次集成自动运行构建和测试 |
| CD (Delivery) | Continuous Delivery(持续交付) | 在 CI 基础上,代码随时可以手动触发部署到生产环境 |
| CD (Deployment) | Continuous Deployment(持续部署) | 更进一步,代码通过所有检查后自动部署到生产环境 |
一句话理解: CI 保证"代码没问题",CD 保证"代码能上线"。
代码提交 → 自动编译 → 自动测试 → 自动构建 → [手动/自动] 部署
CI CD
6.2 GitLab CI 的工作原理
GitLab CI 通过一个 .gitlab-ci.yml 文件来定义流水线,放在仓库根目录:
项目根目录/
├── .gitlab-ci.yml ← CI/CD 配置文件
├── src/
├── pom.xml
└── ...
核心概念:
| 概念 | 说明 |
|---|---|
| Pipeline | 一次完整的 CI/CD 执行,包含所有 Stage |
| Stage | 流水线的阶段(如 build → test → deploy),按顺序执行 |
| Job | 每个 Stage 里的具体任务,同一个 Stage 的 Job 并行执行 |
| Runner | 实际执行 Job 的机器(可以是 Docker、Shell、K8s 等) |
Pipeline
│
├── Stage: build → [Job: compile] [Job: package]
│ ↓
├── Stage: test → [Job: unit-test] [Job: integration-test]
│ ↓
└── Stage: deploy → [Job: deploy-staging] → [Job: deploy-prod]
6.3 第一个 .gitlab-ci.yml
yaml
# 定义流水线的阶段
stages:
- build
- test
- deploy
# 编译任务
build-job:
stage: build
script:
- echo "开始编译..."
- mvn clean compile
tags:
- java-runner
# 单元测试任务
test-job:
stage: test
script:
- echo "运行单元测试..."
- mvn test
tags:
- java-runner
# 部署任务
deploy-job:
stage: deploy
script:
- echo "部署到测试环境..."
- echo "scp target/app.jar server:/opt/app/"
tags:
- java-runner
only:
- main # 只在 main 分支触发部署
上面的配置做了什么?
- 每次 push 代码,GitLab 自动创建一条 Pipeline
- 先执行
build-job(编译) - 编译成功后,执行
test-job(测试) - 测试通过后,如果是 main 分支,执行
deploy-job(部署)
6.4 更贴近实战的 Pipeline
yaml
stages:
- build
- test
- package
- deploy
variables:
MAVEN_OPTS: "-Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository"
APP_NAME: "my-app"
# 缓存 Maven 依赖,加速后续构建
cache:
key: "${CI_COMMIT_REF_SLUG}"
paths:
- .m2/repository/
# 编译
build:
stage: build
script:
- mvn clean compile -q
artifacts:
paths:
- target/classes/
expire_in: 1 hour
# 单元测试
unit-test:
stage: test
script:
- mvn test -q
artifacts:
reports:
junit: target/surefire-reports/TEST-*.xml
expire_in: 1 week
# 代码质量检查
code-check:
stage: test
script:
- mvn checkstyle:check -q
allow_failure: true # 允许失败,不阻塞流水线
# 打包
package:
stage: package
script:
- mvn package -DskipTests -q
artifacts:
paths:
- target/*.jar
expire_in: 1 week
only:
- main
- release/*
# 部署到测试环境
deploy-staging:
stage: deploy
script:
- echo "部署到测试环境"
- scp target/*.jar deploy@staging-server:/opt/$APP_NAME/
- ssh deploy@staging-server "systemctl restart $APP_NAME"
environment:
name: staging
url: http://staging.example.com
only:
- main
# 部署到生产环境(手动触发)
deploy-production:
stage: deploy
script:
- echo "部署到生产环境"
- scp target/*.jar deploy@prod-server:/opt/$APP_NAME/
- ssh deploy@prod-server "systemctl restart $APP_NAME"
environment:
name: production
url: https://www.example.com
when: manual # 需要手动点击触发
only:
- main
6.5 常用关键词详解
| 关键词 | 说明 | 示例 |
|---|---|---|
stages |
定义流水线阶段和执行顺序 | stages: [build, test, deploy] |
script |
Job 要执行的命令 | script: mvn test |
stage |
指定 Job 属于哪个阶段 | stage: build |
only / rules |
控制 Job 在哪些分支/条件触发 | only: [main] |
when |
控制 Job 的执行时机 | when: manual / on_failure / always |
artifacts |
保存构建产物,供后续 Job 使用 | 编译产物、测试报告 |
cache |
缓存依赖,加速后续构建 | Maven/Node 依赖 |
tags |
指定哪个 Runner 执行这个 Job | tags: [java-runner] |
allow_failure |
允许失败不阻塞流水线 | 代码检查类 |
environment |
声明部署环境 | staging / production |
dependencies |
指定依赖哪些 Job 的 artifacts | dependencies: [build] |
needs |
跨 Stage 依赖(不等整个 Stage 完成) | needs: ["build"] |
before_script |
在所有 script 之前执行 | 安装依赖 |
after_script |
在 script 之后执行(即使失败) | 清理资源 |
6.6 触发规则(rules)
yaml
# 现代写法推荐用 rules 代替 only/except
test-job:
stage: test
script:
- mvn test
rules:
# main 分支:总是执行
- if: '$CI_COMMIT_BRANCH == "main"'
when: always
# MR 到 main:总是执行
- if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "main"'
when: always
# feature 分支:只在有代码变更时执行
- if: '$CI_COMMIT_BRANCH =~ /^feature/'
changes:
- src/**/*
when: manual
6.7 Runner 简介
Runner 是实际执行 Job 的"工人"。
| 类型 | 说明 |
|---|---|
| Specific Runner | 绑定到特定项目,只有该项目能用 |
| Shared Runner | GitLab 实例级别的公共 Runner,所有项目可用 |
| Group Runner | 绑定到某个 Group,组内项目可用 |
Runner 的执行方式:
| 执行器 | 说明 |
|---|---|
shell |
直接在 Runner 机器上执行命令 |
docker |
在 Docker 容器中执行(推荐,环境隔离) |
kubernetes |
在 K8s Pod 中执行(弹性伸缩) |
ssh |
在远程机器上执行 |
🎯 面试常问:CI/CD 流水线中如何保证构建环境的一致性?
答:使用 Docker 执行器,每个 Job 在独立的容器中运行,通过
image指定基础镜像,确保每次构建环境完全一致。
七、Pipeline 触发条件与变量
7.1 常见触发场景
| 场景 | 触发方式 |
|---|---|
| Push 代码 | 自动触发 |
| 创建/更新 MR | 自动触发(MR Pipeline) |
| 定时任务 | Schedule 配置 |
| 手动触发 | 点击 Pipeline 页面的 "Run Pipeline" |
| Webhook | 外部系统调用 API 触发 |
| Tag 创建 | git tag 推送后触发 |
7.2 预定义变量
GitLab CI 内置了大量环境变量,可以直接使用:
yaml
deploy:
script:
- echo "项目路径: $CI_PROJECT_DIR"
- echo "分支名: $CI_COMMIT_BRANCH"
- echo "提交SHA: $CI_COMMIT_SHA"
- echo "提交信息: $CI_COMMIT_MESSAGE"
- echo "Pipeline ID: $CI_PIPELINE_ID"
- echo "Job ID: $CI_JOB_ID"
- echo "触发者: $GITLAB_USER_LOGIN"
7.3 自定义变量(CI/CD Settings)
敏感信息(数据库密码、API Key)不要硬编码在 .gitlab-ci.yml 中,通过 GitLab 的 CI/CD 变量管理:
GitLab → Settings → CI/CD → Variables
yaml
deploy:
script:
# 使用在 GitLab 中配置的变量
- echo "Deploying to $DEPLOY_HOST"
- ssh deploy@$DEPLOY_HOST "restart app"
variables:
DEPLOY_HOST: "192.168.1.100" # 也可以直接在 yml 中定义非敏感变量
| 变量类型 | 说明 |
|---|---|
| Variable | 普通变量 |
| File | 值为文件内容(如 SSH Key、配置文件) |
| Masked | 在 Job 日志中自动遮掩(****) |
| Protected | 只在受保护分支/Tag 的 Pipeline 中可用 |
八、从 0 到 1 跑通 CI/CD 实战
8.1 前置条件
- 一个 GitLab 仓库(已有 Java Spring Boot 项目)
- 一台安装了 GitLab Runner 的机器
- Runner 已注册并关联到你的项目
8.2 创建 .gitlab-ci.yml
yaml
stages:
- build
- test
- package
- deploy
# ====== 编译 ======
compile:
stage: build
image: maven:3.8-openjdk-17
script:
- mvn clean compile
cache:
key: maven-cache
paths:
- .m2/repository/
# ====== 测试 ======
unit-test:
stage: test
image: maven:3.8-openjdk-17
script:
- mvn test
artifacts:
reports:
junit: target/surefire-reports/TEST-*.xml
# ====== 打包 ======
package:
stage: package
image: maven:3.8-openjdk-17
script:
- mvn package -DskipTests
artifacts:
paths:
- target/*.jar
expire_in: 1 week
only:
- main
# ====== 部署 ======
deploy:
stage: deploy
script:
- echo "部署中..."
only:
- main
when: manual
8.3 验证流水线
- Push
.gitlab-ci.yml到仓库 - 打开 GitLab → CI/CD → Pipelines
- 观察 Pipeline 执行状态
- 每个 Stage 完成后检查 Job 日志
- 全部通过后,手动触发 deploy
💡 调试技巧:Pipeline 失败时,点击对应 Job 查看完整日志。常见问题包括:依赖下载超时(加 cache)、测试用例失败、Runner 不可用等。
九、常见问题与排查
9.1 MR 合并冲突
bash
# 本地解决冲突
git checkout main
git pull origin main
git checkout feature/xxx
git rebase main # 或 git merge main
# 解决冲突文件
# ... 手动编辑 ...
git add .
git commit
git push
# MR 会自动更新
9.2 Pipeline 一直 pending
原因通常是没有可用的 Runner:
- 检查 Runner 是否在线:
gitlab-runner verify - 检查 Runner 的 tag 是否与 Job 的 tags 匹配
- 检查 Runner 是否被分配到了你的项目
9.3 缓存不生效
- 检查
cache.key是否合理(太频繁变化会导致缓存失效) - 检查 Runner 类型(Docker 执行器需要挂载 volume 才能持久化缓存)
- 使用
cache:fallback_keys设置降级缓存
思维导图速览
GitLab 协作与 CI/CD
│
├── GitLab 基础
│ ├── 创建项目 / 推送代码
│ ├── SSH Key 配置
│ └── 分支保护策略
│
├── MR 合并请求流程
│ ├── 创建 MR(分支 → main)
│ ├── 填写描述、指定 Reviewer
│ ├── 合并策略(merge / squash / rebase)
│ └── MR 模板(统一规范)
│
├── 代码 Review
│ ├── 关注点:逻辑 > 安全 > 性能 > 可维护 > 风格
│ ├── 评论规范(🔴必改 / 🟡建议 / 🟢讨论 / 💡Nitpick)
│ ├── Approve 机制
│ └── CODEOWNERS 自动分配 Reviewer
│
├── 分支策略
│ ├── Git Flow(main + develop + feature + release + hotfix)
│ ├── GitHub Flow(main + feature,简化版)
│ └── 团队规范:所有 push 走 MR,CI/CD 通过才允许合并
│
├── CI/CD 入门
│ ├── CI:持续集成(自动编译、测试、检查)
│ ├── CD:持续交付/部署(自动/手动部署)
│ ├── .gitlab-ci.yml 配置
│ │ ├── stages → jobs → script
│ │ ├── artifacts / cache / rules
│ │ └── 变量管理(敏感信息走 CI/CD Settings)
│ └── Runner(执行器:Shell / Docker / K8s)
│
└── 实战流程
└── push → Pipeline → build → test → package → deploy
写在最后
GitLab 把 Git 从一个"命令行工具"升级成了一个"团队协作平台"。核心就三件事:
-
代码托管 + 权限控制:谁能看、谁能改、谁有分支保护,都在 GitLab 上管。
-
MR 驱动开发:所有变更走 MR,强制 Review + CI 通过才能合并。这是团队协作的生命线。
-
CI/CD 自动化 :
.gitlab-ci.yml写一次,以后每次 push 自动跑构建、测试、部署。解放双手,减少人为错误。
面试中怎么聊这些?
- 不要只说"我用了 Git",要说"我们团队采用 MR 工作流,所有代码变更必须通过 MR 合并,CI/CD Pipeline 跑通后才允许合并"。
- 如果能结合自己的项目说"我配置了 GitLab CI 流水线,包含编译、单元测试、打包、部署四个阶段",那就是加分项。