核心理念:dev 持续集成,release 定期发布,hotfix 统一修复。所有修复由开发者主动合并到目标分支,减少分支类型。
dev(持续集成主干,保护分支)
├── feature/skill-system(新功能开发1)
├── feature/new-level(新功能开发1)
├── release/v1.0.0(测试+发布分支,生命周期=发布周期)
│ └── hotfix/crash-issue(从 release 切出的修复,合并回 release + dev)
└── hotfix/v1.0.1-pay-bug(线上热修复,从 Tag 创建,合并回 dev + 新 Tag)
└── tag:v1.0.1(线上运维的版本)
graph LR
subgraph 开发阶段
dev(dev: 持续集成) --> feature[feature/*: 新功能]
feature --> |PR合并| dev
dev --> |创建| release[release/vX.X.X: 待发布/维护分支]
end
subgraph 测试阶段
release --> |发现Bug| hotfix[hotfix/*: Bug修复]
hotfix --> |合并| release
hotfix --> |合并| dev
end
subgraph 发布阶段
release --> |测试通过| tag[tag: vX.X.X]
end
subgraph 线上运维
release --> |线上Bug| hotfix
hotfix --> |打新Tag| tag2[Tag: vX.X.Y]
end
style dev fill:#f9f,stroke:#333,stroke-width:1px
style tag fill:#bbf,stroke:#333,stroke-width:1px
style tag2 fill:#bbf,stroke:#333,stroke-width:1px
style release fill:#bbf,stroke:#333,stroke-width:1px
# 1.1 同步最新主干
git checkout dev
git pull origin dev
# 1.2 创建功能分支
git checkout -b feature/player-combat
# 1.3 开发并提交
git add .
git commit -m "feat: 实现三段连击系统
- 添加跳跃状态机
- 实现空中伤害判定
- 关联任务:PROG-789"
git push origin feature/player-combat
# 1.4 提交 Pull Request 到 dev
# Code Review 通过后合并
# 1.5 合并后立即删除功能分支
git checkout dev
git pull origin dev
git branch -d feature/player-combat
git push origin --delete feature/player-combat
原则:dev 永不冻结,始终接收新功能,CI 自动构建供开发自测。
# 2.1 发布负责人创建 release 分支
git checkout dev
git pull origin dev
git checkout -b release/v1.0.0
git push origin release/v1.0.0
# 2.2 CI 自动触发测试包构建
# GitLab/GitHub 检测到 release/v* 分支自动打包
状态切换:从这一刻起,dev 继续接收新功能,release/v1.0.0 只接收修复。
# 3.1 QA 在 release 上发现 Bug
# 开发者从 release 切 hotfix 分支
git checkout release/v1.0.0
git checkout -b hotfix/crash-issue
# 3.2 修复并提交
git add .
git commit -m "hotfix: 修复商城崩溃
- 空数据保护
- 发现阶段:QA测试
- 影响版本:release/v1.0.0"
git push origin hotfix/crash-issue
# 3.3 提交 PR 到 release/v1.0.0
# Reviewer:QA负责人 + 主程
# 3.4 合并到 release(操作人:主程)
git checkout release/v1.0.0
git merge hotfix/crash-issue --no-ff
git push origin release/v1.0.0
# 3.5 主动合并回 dev(操作人:开发者自己)
git checkout dev
git pull origin dev
git merge hotfix/crash-issue --no-ff
git push origin dev
# 3.6 删除 hotfix 分支
git branch -d hotfix/crash-issue
git push origin --delete hotfix/crash-issue
关键点:合并到 dev 是开发者的责任,不是自动的。如果冲突,需手动解决并保证代码兼容。
# 4.1 QA 测试通过,批准发布
git checkout release/v1.0.0
git pull origin release/v1.0.0
# 4.2 打正式版本 Tag(这就是线上版本的锚定点)
git tag -a v1.0.0 -m "正式版本 v1.0.0 发布
- 构建号:#12345
- 发布日期:2024-12-08"
git push origin v1.0.0
# 4.3 删除 release 分支(保持整洁)
git branch -d release/v1.0.0
git push origin --delete release/v1.0.0
原则:发布后,release/v1.0.0 已完成使命,Tag v1.0.0 是唯一定位方式。
# 5.1 线上 v1.0.0 出现紧急 Bug
# 必须从 Tag 创建 hotfix 分支
git fetch origin tag v1.0.0
git checkout -b hotfix/v1.0.1-pay-bug v1.0.0
# 5.2 修复并提交
git add .
git commit -m "hotfix: 修复支付失败
- 支付宝SDK版本回退
- 发现阶段:线上监控
- 紧急程度:P0"
git push origin hotfix/v1.0.1-pay-bug
# 5.3 打热修复版本 Tag
git tag -a v1.0.1 -m "热修复版本 v1.0.1"
git push origin v1.0.1
# 5.4 合并回 dev(开发者的责任)
git checkout dev
git pull origin dev
git merge hotfix/v1.0.1-pay-bug --no-ff
git push origin dev
# 5.5 删除 hotfix 分支
git branch -d hotfix/v1.0.1-pay-bug
git push origin --delete hotfix/v1.0.1-pay-bug
注意:如果 dev 已重构导致无法合并,需手动移植修复逻辑。
<type>: <简短描述(50字符内)>
[正文]
- 改动细节1
- 改动细节2
[发现阶段:QA测试/线上监控/开发自测]
[影响范围:release/v1.0.0 / v1.0.0 / dev]
[关联任务:TASK-123]
| 类型 | 说明 | 使用分支 |
|---|---|---|
featture |
新功能 | feature/* → dev |
hotfix |
Bug修复/热修复 | hotfix/* → release/dev/Tag |
refactor |
重构 | feature/* → dev |
art |
美术资源 | art/* → model1 |
# 功能开发
feat: 新增联盟系统
- 创建/加入/退出联盟
- 联盟聊天功能
- 关联任务:PROG-456
# 测试阶段修复
hotfix: 修复角色穿模
- 调整碰撞盒大小
- 发现阶段:QA测试
- 影响版本:release/v1.0.0
# 线上热修复
hotfix: 修复支付回调失败
- 回滚SDK到3.2.1
- 发现阶段:线上监控
- 紧急程度:P0
- 影响版本:v1.0.0
#!/bin/bash
# scripts/create-release.sh
if [ -z "$1" ]; then
echo "用法: ./create-release.sh v1.0.0"
exit 1
fi
VERSION=$1
# 必须在 dev 分支
current_branch=$(git symbolic-ref HEAD | sed 's!refs\/heads\/!!')
if [ "$current_branch" != "dev" ]; then
echo "❌ 必须在 dev 分支创建 release"
exit 1
fi
# 同步并创建
git pull origin dev
git checkout -b release/$VERSION
git push origin release/$VERSION
echo "✅ release/$VERSION 已创建"
echo "请通知 QA 开始测试"
#!/bin/bash
# scripts/create-hotfix.sh
if [ -z "$1" ] || [ -z "$2" ]; then
echo "用法: ./create-hotfix.sh <版本> <问题描述>"
echo " 线上Bug: ./create-hotfix.sh v1.0.0 pay-crash"
echo " 测试Bug: ./create-hotfix.sh release/v1.0.0 ui-bug"
exit 1
fi
TARGET=$1
NAME=$2
# 判断是线上还是测试
if [[ "$TARGET" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
# 从 Tag 创建(线上热修复)
git fetch origin tag $TARGET
git checkout -b hotfix/${TARGET}-${NAME} $TARGET
echo "✅ 线上热修复分支 hotfix/${TARGET}-${NAME} 已创建"
else
# 从 release 创建(测试Bug修复)
git fetch origin $TARGET
git checkout -b hotfix/${TARGET#release/}-${NAME} $TARGET
echo "✅ 测试修复分支 hotfix/${TARGET#release/}-${NAME} 已创建"
fi
#!/bin/bash
# scripts/publish.sh
if [ -z "$1" ]; then
echo "用法: ./publish.sh release/v1.0.0"
exit 1
fi
RELEASE=$1
VERSION=${RELEASE#release/}
# 同步 release
git checkout $RELEASE
git pull origin $RELEASE
# 打 Tag
git tag -a $VERSION -m "正式发布 $VERSION"
git push origin $VERSION
# 删除 release 分支
git branch -d $RELEASE
git push origin --delete $RELEASE
echo "🎉 发布完成!Tag: $VERSION"
# .gitlab-ci.yml
stages:
- build
- test
- deploy
variables:
UNITY_PATH: "/opt/Unity/Editor/Unity"
# ==================== dev 快速构建 ====================
build:dev:
stage: build
script:
- $UNITY_PATH -batchmode -projectPath . -buildWindows64Player Build/Dev/Game.exe
artifacts:
paths: [Build/Dev/]
expire_in: 2 days
only:
- dev
tags: [unity-builder]
# ==================== release 测试包 ====================
build:release:
stage: build
script:
- $UNITY_PATH -batchmode -projectPath . -buildWindows64Player Build/Release/Game.exe
- $UNITY_PATH -batchmode -projectPath . -buildAndroidPlayer Build/Release/Game.apk
artifacts:
paths: [Build/Release/]
expire_in: 1 week
only:
- /^release\/v.*$/
tags: [unity-builder]
# ==================== hotfix 快速验证 ====================
build:hotfix:
stage: build
script:
- $UNITY_PATH -batchmode -projectPath . -buildWindows64Player Build/Hotfix/Game.exe
artifacts:
paths: [Build/Hotfix/]
expire_in: 1 day
only:
- /^hotfix\/.*$/
tags: [unity-builder]
# ==================== Tag 正式包 ====================
build:production:
stage: build
script:
- echo "构建正式版本: $CI_COMMIT_TAG"
- $UNITY_PATH -batchmode -projectPath . -buildWindows64Player Build/Prod/Game_$CI_COMMIT_TAG.exe
artifacts:
paths: [Build/Prod/]
expire_in: 30 days
only:
- /^v\d+\.\d+\.\d+$/
tags: [unity-builder]
# ==================== 部署到 Steam ====================
deploy:steam:
stage: deploy
script:
- python scripts/upload_steam.py Build/Prod/Game_$CI_COMMIT_TAG.exe
only:
- /^v\d+\.\d+\.\d+$/
when: manual
tags: [deploy]
| 操作 | 开发者 | QA | 主程 | 备注 |
|---|---|---|---|---|
推送 dev |
❌ | ❌ | ❌ | 必须通过 PR |
合并 PR 到 dev |
❌ | ❌ | ✅ | 需 1 名 reviewer |
创建 release/* |
❌ | ❌ | ✅ | 由发布负责人操作 |
推送 hotfix/* |
✅ | ❌ | ✅ | 开发者创建修复 |
合并到 release/* |
❌ | ❌ | ✅ | 需 QA + 主程批准 |
| 打版本 Tag | ❌ | ❌ | ✅ | 仅发布负责人 |
| 删除远程分支 | ❌ | ❌ | ✅ | 每周清理 |
feature → dev PR:
hotfix → release PR:
hotfix → dev PR(线上热修复后):
1. dev 分支状态:CI 是否通过 / 有多少待合并 PR
2. release 状态:当前测试版本 / blocking bug 数量
3. hotfix 状态:是否在修复 / 预计合并时间
4. 代码冻结通知:今天 18:00 冻结 dev,准备发布 v1.0.0
# 步骤 1:暂停合并,通知主程
git checkout dev
git merge hotfix/v1.0.1-crash
# 步骤 2:主程评估冲突范围
# 如果冲突文件 > 5 个或涉及核心模块:
git merge --abort
# 步骤 3:在 dev 上重新实现修复
git checkout dev
git checkout -b hotfix/v1.0.1-dev
# 手动移植修复逻辑,适配新架构
# 步骤 4:合并到 dev,关闭原 hotfix PR
git checkout dev
git merge hotfix/v1.0.1-dev --no-ff
# 策略:release 分支继续保留,dev 继续开发
# 但需要在 release 上合并 dev 的部分修复
# 步骤 1:判断 dev 上的某个 commit 是否需要
git checkout release/v1.0.0
git cherry-pick <commit-hash> # 只合并必要的修复
# 步骤 2:通知团队,哪些 dev 的修复已合并到 release
# 避免重复修复
# 步骤 3:发布完成后,release 合并回 dev(一次性)
git checkout dev
git merge release/v1.0.0 --no-ff
# v1.0.0 国内版,v1.1.0 海外版,发现共用 Bug
# 步骤 1:从 v1.0.0 切 hotfix
git checkout -b hotfix/v1.0.1-bug v1.0.0
# ...修复...
# 步骤 2:从 v1.1.0 切 hotfix
git checkout -b hotfix/v1.1.1-bug v1.1.0
# cherry-pick 修复 commit
git cherry-pick hotfix/v1.0.1-bug
# 步骤 3:分别打 Tag 发布
# v1.0.1 发国内渠道,v1.1.1 发海外渠道
# 步骤 4:合并回 dev
git checkout dev
git merge hotfix/v1.1.1-bug --no-ff
[alias]
# 查看分支图
lg = log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit
# 创建 hotfix(自动判断来源)
hf = "!f() { if [[ \"$1\" =~ ^v ]]; then git fetch origin tag $1 && git checkout -b hotfix/$2 $1; else git fetch origin $1 && git checkout -b hotfix/${1#release/}-$2 $1; fi; }; f"
# 清理已合并分支
cleanup = "!git branch --merged | grep -vE '(^\\*|dev|release)' | xargs git branch -d"
# 查看当前活跃分支
active = "!git branch -r | grep -E '(feature|hotfix)' | grep -v ' merged$'"
[push]
default = simple
followTags = true
使用示例:
git hf release/v1.0.0 ui-bug # 从 release 创建测试修复
git hf v1.0.0 pay-crash # 从 Tag 创建热修复
git cleanup # 删除本地已合并分支
git active # 查看团队活跃分支
# .git/hooks/pre-push(客户端)
#!/bin/sh
PROTECTED="dev release/"
current=$(git symbolic-ref HEAD | sed 's!refs/heads/!!')
if [[ "$current" =~ $PROTECTED ]]; then
echo "❌ 不能直接推送 $current 分支!"
echo " 请使用 Pull Request 流程"
exit 1
fi
# 代码文件(不使用 LFS)
*.cs text diff=csharp
*.cpp text diff=cpp
*.h text diff=cpp
*.lua text
# 美术资源(使用 LFS)
*.psd filter=lfs diff=lfs merge=lfs -text
*.fbx filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text
*.tga filter=lfs diff=lfs merge=lfs -text
*.exr filter=lfs diff=lfs merge=lfs -text
# 音频资源
*.wav filter=lfs diff=lfs merge=lfs -text
*.mp3 filter=lfs diff=lfs merge=lfs -text
*.bank filter=lfs diff=lfs merge=lfs -text
# 构建产物
*.apk filter=lfs diff=lfs merge=lfs -text
*.ipa filter=lfs diff=lfs merge=lfs -text
*.dll filter=lfs diff=lfs merge=lfs -text
Q1: 如何区分"测试修复"和"线上热修复"?
A: 通过提交信息和来源区分:
git log 显示 hotfix: xxx 且父分支是 release/*git log 显示 hotfix: xxx 且父分支是 Tag vX.X.Xgit show --stat 查看分支来源Q2: 如果开发者忘记合并 hotfix 回 dev 怎么办?
A: 通过 CI 和每周检查防止:
hotfix/* 合并到 release 后,必须存在到 dev 的 PRQ3: release 分支可以保留吗?
A: 可以,但有代价:
archive/v1.0.0,并明确标注已发布#!/bin/bash
# scripts/daily-check.sh
echo "=== 每日分支健康检查 ==="
# 1. dev 分支是否可构建
curl -s "https://gitlab.example.com/api/v4/projects/123/pipelines?ref=dev" |
grep -q "status.*success" && echo "✅ dev 构建正常" || echo "❌ dev 构建失败"
# 2. release 分支数量
release_count=$(git branch -r | grep -c "release/" || true)
if [ $release_count -eq 0 ]; then
echo "✅ 无待发布版本"
elif [ $release_count -eq 1 ]; then
echo "✅ 1 个待发布版本(正常)"
else
echo "⚠️ $release_count 个待发布版本(需关注)"
fi
# 3. 未合并的 hotfix
hotfix_count=$(git branch -r | grep "hotfix/" | wc -l)
if [ $hotfix_count -gt 0 ]; then
echo "⚠️ 有 $hotfix_count 个未删除的 hotfix 分支"
git branch -r | grep "hotfix/"
fi
# 4. 活跃 feature 分支
echo "活跃功能分支:"
git branch -r | grep "feature/" | head -5
./scripts/publish.sh release/vX.X.Xgraph TD
subgraph "开发"
A[开发者] -->|创建| B(feature/*)
B -->|PR| C(dev)
C -->|CI| D[构建成功]
end
subgraph "发布"
D -->|定时| E[创建 release/vX.X.X]
E -->|QA测试| F{Bug?}
F -->|是| G[hotfix/*]
G -->|合并| E
G -->|合并| C
F -->|否| H[tag vX.X.X]
end
subgraph "运维"
H -->|线上Bug| I[hotfix/vX.X.Y]
I -->|合并| C
I -->|打tag| J[tag vX.X.Y]
end
style C fill:#f9f,stroke:#333,stroke-width:1px
style H fill:#bbf,stroke:#333,stroke-width:1px