**
一、问题背景:为什么我们需要规范Git工作流?
三年前,我所在团队只有5个人,大家都在master分支上直接提交,偶尔拉个dev分支。那时候发布靠手动打Tag,冲突了就本地Merge一下,日子还能过。
但随着团队扩张到22人,微服务拆分出6个仓库,问题爆发了:
1. 环境错乱:A同学把未测试完的代码合并到master,B同学直接基于master打包发到了预发环境,导致预发环境挂了3小时。
2. Code Review形同虚设:虽然规定要MR(Merge Request),但为了赶进度,大家习惯性自己点“Merge”,导致线上代码风格五花八门,SQL注入漏洞在第4次迭代才被发现。
3. CI/CD掉链子:每次合并到master触发Jenkins构建,平均耗时12分钟,且经常因为环境变量冲突导致构建失败,部署成功率只有72%。
痛定思痛,我们决定重新设计Git工作流。目标很明确:既要保证发布稳定性,又不能把开发效率拖垮。
二、环境与版本
在开始配置前,先明确我们的技术栈版本(不同版本配置语法差异较大):
- Git: 2.40.1 (启用了 feature.manyFiles 和 index.version=4 以加速大仓库操作)
- 代码托管: GitLab CE 16.8.2 (自带CI/CD,但我们也接入了外部Jenkins)
- CI/CD: Jenkins 2.426.1 + GitLab Plugin 1.7.16 + SonarQube Scanner 5.0
- 制品库: Nexus 3.58
- 代码质量: SonarQube 10.3
三、方案设计:混合分支模型
纯Git Flow太重,纯Trunk-Based对测试覆盖率要求极高(需>80%)。我们采用了 “简化版Git Flow + 短生命周期Feature分支” 的混合模式:
| 分支名 | 生命周期 | 来源 | 合并目标 | 说明 |
|---|---|---|---|---|
main |
永久 | - | - | 与生产环境完全一致,每次合并打Tag |
release/* |
2周 | main |
main |
发布候选,只修Bug不加Feature |
feature/* |
sonar -> build。注意这里使用了rules替代过时的only/except。 |
# .gitlab-ci.yml
stages:
- test
- sonar
- build
variables:
MAVEN_OPTS: "-Dmaven.repo.local=.m2/repository"
SONAR_HOST_URL: "http://sonarqube.internal:9000"
# 缓存加速
cache:
key: "$CI_COMMIT_REF_SLUG"
paths:
- .m2/repository/
unit-test:
stage: test
image: maven:3.9.6-eclipse-temurin-17
script:
- mvn clean test -Dspring.profiles.active=test
artifacts:
when: always
reports:
junit:
- target/surefire-reports/TEST-*.xml
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: '$CI_COMMIT_BRANCH == "main"'
sonar-scan:
stage: sonar
image: sonarsource/sonar-scanner-cli:5.0
dependencies:
- unit-test
script:
- sonar-scanner
-Dsonar.projectKey=$CI_PROJECT_PATH_SLUG
-Dsonar.qualitygate.wait=true
-Dsonar.gitlab.commit_sha=$CI_COMMIT_SHA
-Dsonar.gitlab.ref_name=$CI_COMMIT_REF_NAME
allow_failure: false
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
build-image:
stage: build
image: docker:24.0.7
services:
- docker:24.0.7-dind
script:
- docker build -t registry.internal/$CI_PROJECT_PATH:$CI_COMMIT_SHORT_SHA .
- docker push registry.internal/$CI_PROJECT_PATH:$CI_COMMIT_SHORT_SHA
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
when: manual # 需要手动点击部署,防止误触发
关键点:sonar.qualitygate.wait=true 让流水线同步等待SonarQube结果,如果不达标,Pipeline直接失败,MR无法合并。
3. Jenkins 集成配置(针对老旧系统)
部分遗留系统无法迁移GitLab CI,我们通过Jenkins的Multibranch Pipeline实现类似逻辑。以下是Jenkinsfile片段:
// Jenkinsfile
pipeline {
agent any
tools {
maven 'Maven-3.9.6'
jdk 'JDK-17'
}
triggers {
// 每分钟轮询GitLab,实际生产建议用Webhook
pollSCM('* * * * *')
}
stages {
stage('Checkout & Build') {
steps {
checkout scm
sh 'mvn clean compile -DskipTests'
}
}
stage('Code Review Gate') {
steps {
// 调用GitLab API检查MR的Approve状态
script {
def response = sh(
script: "curl -s --header 'PRIVATE-TOKEN: ${GITLAB_TOKEN}' '${GITLAB_URL}/api/v4/projects/${PROJECT_ID}/merge_requests/${CHANGE_ID}/approvals'",
returnStdout: true
)
def json = readJSON text: response
if (json.approved_by.size() < 1) {
error "Code Review未通过,至少需要1人Approve!当前Approve数: ${json.approved_by.size()}"
}
}
}
}
stage('SonarQube Analysis') {
steps {
withSonarQubeEnv('SonarQube-Server') {
sh 'mvn sonar:sonar -Dsonar.qualitygate.wait=true'
}
}
}
stage('Deploy to Staging') {
when {
branch 'main'
}
steps {
sh 'kubectl apply -f k8s/staging/ --record'
}
}
}
post {
failure {
// 钉钉通知
sh "curl -X POST -H 'Content-Type: application/json' -d '{\"msgtype\": \"text\", \"text\": {\"content\": \"构建失败: ${env.JOB_NAME} - ${env.BUILD_NUMBER}\"}}' ${DINGTALK_WEBHOOK}"
}
}
}
五、踩坑与优化
坑1:SonarQube扫描太慢导致开发等待
初期每次MR扫描耗时6-8分钟,开发抱怨“喝杯咖啡回来还没好”。优化方案:将Sonar扫描从全量改为增量扫描(只扫描变更文件),并开启sonar.scm.disabled=true(因为GitLab插件已提供变更集),时间降至2分10秒。
坑2:CI缓存导致构建不一致
Maven的.m2缓存偶尔导致依赖冲突。解决方案:每周一凌晨定时清理缓存,并在cache配置中增加policy: pull-push。
坑3:Hotfix分支合并冲突
紧急修复时,hotfix分支从main拉出,修复后合回main,但忘了合回release,导致下次发布代码丢失。解决方案:编写了一个GitLab Webhook脚本,当hotfix/*合并到main时,自动创建MR合并到最新的release/*分支。
六、效果数据
实施该工作流6个月后,我们统计了以下数据(对比实施前3个月):
| 指标 | 实施前 | 实施后 | 变化 |
|---|---|---|---|
| 生产环境事故数 | 7次/季 | 2.8次/季 | -60% |
| MR平均合并耗时 | 4.2小时 | 2.3小时 | -45% |
| CI流水线成功率 | 72% | 94% | +22% |
| 代码覆盖率 | 51% | 68% | +17% |
| 回滚次数 | 5次/季 | 1次/季 | -80% |
总结
Git工作流不是越复杂越好,关键是平衡控制与效率。我们的混合分支策略核心在于:main分支绝对干净,feature分支短平快,用自动化工具(SonarQube + Jenkins/GitLab CI)代替人工检查。如果你也在为团队协作混乱头疼,不妨从配置CODEOWNERS和强制流水线开始,先跑起来,再迭代。记住,工具是死的,流程是活的,适合团队的才是最好的。