第 7 章 - 多项目管理
第 7 章 - 多项目管理
随着团队和项目数量增长,如何设计合理的组织架构、团队结构和权限继承体系变得至关重要。
7.1 组织架构设计
7.1.1 常见组织模型
| 模型 | 适用场景 | 示例 |
|---|---|---|
| 按部门划分 | 传统企业 | 前端部、后端部、运维部 |
| 按产品划分 | 产品驱动型 | 电商平台、内部工具、数据分析 |
| 按服务划分 | 微服务架构 | 用户服务、订单服务、支付服务 |
| 混合模型 | 中大型企业 | 部门 + 产品线交叉 |
7.1.2 Gitea/Forgejo 组织设计
Organizations (组织)
├── platform (平台部)
│ ├── Teams
│ │ ├── frontend (前端团队)
│ │ ├── backend (后端团队)
│ │ └── devops (运维团队)
│ └── Repositories
│ ├── web-app (前端 + 后端)
│ ├── api-gateway (后端 + 运维)
│ └── shared-lib (前端 + 后端)
│
├── product (产品部)
│ ├── Teams
│ │ ├── mobile (移动端)
│ │ └── data (数据团队)
│ └── Repositories
│ ├── ios-app
│ ├── android-app
│ └── data-pipeline
│
└── infra (基础设施)
├── Teams
│ └── sre
└── Repositories
├── terraform
├── ansible
└── monitoring
7.1.3 通过 API 创建组织和团队
GITEA_URL="https://git.example.com"
TOKEN="your_admin_token"
# 创建组织
create_org() {
curl -s -X POST -H "Authorization: token $TOKEN" \
-H "Content-Type: application/json" \
"$GITEA_URL/api/v1/orgs" \
-d "{
\"username\": \"$1\",
\"full_name\": \"$2\",
\"description\": \"$3\",
\"visibility\": \"limited\"
}" | jq '.id'
}
ORG_ID=$(create_org "platform" "平台部" "平台技术团队")
# 创建团队
create_team() {
curl -s -X POST -H "Authorization: token $TOKEN" \
-H "Content-Type: application/json" \
"$GITEA_URL/api/v1/orgs/$1/teams" \
-d "{
\"name\": \"$2\",
\"description\": \"$3\",
\"permission\": \"$4\",
\"units\": [\"repo.code\", \"repo.issues\", \"repo.pulls\", \"repo.releases\"]
}"
}
create_team "platform" "frontend" "前端团队" "write"
create_team "platform" "backend" "后端团队" "write"
create_team "platform" "devops" "运维团队" "admin"
7.1.4 GitLab Group 嵌套结构
GitLab 支持 Group 嵌套,适合更复杂的组织架构:
Group: company (顶层)
├── SubGroup: engineering
│ ├── SubGroup: frontend
│ │ ├── Project: design-system
│ │ └── Project: web-app
│ ├── SubGroup: backend
│ │ ├── Project: api-server
│ │ └── Project: auth-service
│ └── SubGroup: platform
│ ├── Project: infrastructure
│ └── Project: monitoring
├── SubGroup: product
│ ├── Project: mobile-app
│ └── Project: data-analytics
└── SubGroup: shared
├── Project: docs
└── Project: coding-standards
# 创建顶层 Group
curl -s -X POST -H "PRIVATE-TOKEN: $TOKEN" \
"$GITLAB_URL/api/v4/groups" \
-d '{
"name": "Company",
"path": "company",
"visibility": "internal"
}'
# 创建子 Group
curl -s -X POST -H "PRIVATE-TOKEN: $TOKEN" \
"$GITLAB_URL/api/v4/groups" \
-d '{
"name": "Engineering",
"path": "engineering",
"parent_id": TOP_LEVEL_GROUP_ID,
"visibility": "internal"
}'
# 在子 Group 下创建项目
curl -s -X POST -H "PRIVATE-TOKEN: $TOKEN" \
"$GITLAB_URL/api/v4/projects" \
-d '{
"name": "Web App",
"path": "web-app",
"namespace_id": ENGINEERING_GROUP_ID,
"visibility": "internal"
}'
7.2 权限继承体系
7.2.1 Gitea 权限继承
Organization 权限
├── Owner → 组织 Owner,完全控制
├── Member → 组织成员,自动获得组织仓库的读取权限
│
└── Team 权限(覆盖或补充组织权限)
├── Admin → 团队管理的仓库完全控制
├── Write → 读写
├── Read → 只读
└── 自定义 → 精细权限
规则:用户对仓库的有效权限 = max(组织成员权限, 团队权限)
7.2.2 GitLab 权限继承
Group (Owner: 50)
├── 成员继承规则
│ ├── Group 级别成员 → 自动继承到所有子 Group 和 Project
│ ├── SubGroup 级别成员 → 继承到其下所有子 Group 和 Project
│ └── Project 级别成员 → 仅限该项目
│
├── 权限取最高值
│ User 在 Group=Reporter, 在 Project=Developer → 有效权限 = Developer
│
└── 最大角色传播
Group Owner → 所有子 Group 和 Project 的 Owner
继承示例:
# 在 Group 级别添加成员,自动继承到所有子项目
curl -s -X POST -H "PRIVATE-TOKEN: $TOKEN" \
"$GITLAB_URL/api/v4/groups/GROUP_ID/members" \
-d '{
"user_id": 123,
"access_level": 30
}'
# 用户 123 自动获得该 Group 下所有项目 Developer 权限
7.2.3 权限矩阵设计
| 角色 | 创建仓库 | 推送代码 | 合并 MR | 管理 Issue | 管理项目设置 | 管理成员 |
|---|---|---|---|---|---|---|
| 外部贡献者 | ❌ | Fork 推送 | ❌ | 评论 | ❌ | ❌ |
| 访客 (Guest) | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ |
| 报告者 (Reporter) | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ |
| 开发者 (Developer) | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
| 维护者 (Maintainer) | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| 管理员 (Owner) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
7.3 仓库模板管理
7.3.1 Gitea 组织模板仓库
# 创建模板仓库(在 Web 界面中设置为 Template)
curl -s -X POST -H "Authorization: token $TOKEN" \
-H "Content-Type: application/json" \
"$GITEA_URL/api/v1/orgs/platform/repos" \
-d '{
"name": "template-node-app",
"description": "Node.js 应用模板仓库",
"template": false,
"auto_init": true,
"default_branch": "main"
}'
在模板仓库中预置:
template-node-app/
├── .github/
│ └── ISSUE_TEMPLATE/
│ ├── bug_report.md
│ └── feature_request.md
├── .gitea/
│ └── workflows/
│ └── ci.yml
├── .gitignore
├── .editorconfig
├── .eslintrc.js
├── Dockerfile
├── docker-compose.yml
├── README.md
├── LICENSE
├── package.json
└── src/
└── index.js
7.3.2 GitLab 项目模板
GitLab 支持 Group 级别的项目模板:
# 设置 Group 项目模板
# Web 界面: Group → Settings → General → Templates → Select a template group
# 或通过 API
curl -s -X PUT -H "PRIVATE-TOKEN: $TOKEN" \
"$GITLAB_URL/api/v4/groups/GROUP_ID" \
-d '{
"project_creation_level": "developer",
"subgroup_creation_level": "maintainer",
"default_branch_protection": 2
}'
7.4 分支保护策略
7.4.1 Gitea 分支保护
# 通过 API 设置分支保护
curl -s -X POST -H "Authorization: token $TOKEN" \
-H "Content-Type: application/json" \
"$GITEA_URL/api/v1/repos/owner/repo/branches/main/protection" \
-d '{
"enable_push": true,
"enable_push_whitelist": true,
"push_whitelist_usernames": ["alice", "bob"],
"enable_merge_whitelist": true,
"merge_whitelist_usernames": ["alice"],
"enable_status_check": true,
"status_check_contexts": ["ci/build", "ci/test"],
"required_approvals": 2,
"enable_approvals_whitelist": true,
"approvals_whitelist_usernames": ["alice", "bob"]
}'
7.4.2 GitLab 分支保护规则
# 保护 main 分支
curl -s -X POST -H "PRIVATE-TOKEN: $TOKEN" \
-H "Content-Type: application/json" \
"$GITLAB_URL/api/v4/projects/PROJECT_ID/protected_branches" \
-d '{
"name": "main",
"push_access_level": 40,
"merge_access_level": 30,
"unprotect_access_level": 40,
"allow_force_push": false,
"code_owner_approval_required": true
}'
# 保护 release/* 通配符
curl -s -X POST -H "PRIVATE-TOKEN: $TOKEN" \
"$GITLAB_URL/api/v4/projects/PROJECT_ID/protected_branches" \
-d '{
"name": "release/*",
"push_access_level": 40,
"merge_access_level": 40
}'
7.4.3 分支保护矩阵
| 分支模式 | 保护级别 | 推送权限 | 合并权限 | 适用场景 |
|---|---|---|---|---|
| main | 严格 | Maintainer | Developer(需 Review) | 生产代码 |
| dev | 中等 | Developer | Developer | 开发集成 |
| feature/* | 宽松 | Developer | Developer | 功能开发 |
| release/* | 严格 | Maintainer | Maintainer | 发布管理 |
| hotfix/* | 中等 | Maintainer | Maintainer | 紧急修复 |
7.5 标签和里程碑管理
7.5.1 标签(Labels)标准化
# 批量创建标准标签
GITEA_URL="https://git.example.com"
TOKEN="your_token"
REPO="owner/repo"
labels=(
'{"name":"bug","color":"#d73a4a","description":"Bug 报告"}'
'{"name":"feature","color":"#0075ca","description":"新功能"}'
'{"name":"enhancement","color":"#a2eeef","description":"改进"}'
'{"name":"documentation","color":"#0075ca","description":"文档"}'
'{"name":"good first issue","color":"#7057ff","description":"适合新手"}'
'{"name":"priority:high","color":"#b60205","description":"高优先级"}'
'{"name":"priority:medium","color":"#fbca04","description":"中优先级"}'
'{"name":"priority:low","color":"#0e8a16","description":"低优先级"}'
'{"name":"status:blocked","color":"#e4e669","description":"被阻塞"}'
'{"name":"status:in-progress","color":"#c2e0c6","description":"进行中"}'
'{"name":"status:review","color":"#bfdadc","description":"待审查"}'
'{"name":"team:frontend","color":"#ededed","description":"前端团队"}'
'{"name":"team:backend","color":"#ededed","description":"后端团队"}'
)
for label_json in "${labels[@]}"; do
curl -s -X POST -H "Authorization: token $TOKEN" \
-H "Content-Type: application/json" \
"$GITEA_URL/api/v1/repos/$REPO/labels" \
-d "$label_json" | jq '.name'
done
7.5.2 里程碑管理
# 创建里程碑
curl -s -X POST -H "Authorization: token $TOKEN" \
-H "Content-Type: application/json" \
"$GITEA_URL/api/v1/repos/$REPO/milestones" \
-d '{
"title": "v2.0",
"description": "2.0 版本发布",
"due_on": "2026-08-01T00:00:00+08:00"
}'
7.6 批量管理脚本
7.6.1 仓库批量创建
#!/bin/bash
# batch-create-repos.sh
GITEA_URL="https://git.example.com"
TOKEN="your_token"
ORG="platform"
repos=(
'{"name":"web-app","description":"Web 前端应用","auto_init":true,"default_branch":"main"}'
'{"name":"api-server","description":"API 服务端","auto_init":true,"default_branch":"main"}'
'{"name":"shared-lib","description":"共享库","auto_init":true,"default_branch":"main"}'
'{"name":"design-docs","description":"设计文档","auto_init":true,"default_branch":"main"}'
)
for repo_json in "${repos[@]}"; do
echo "Creating repo..."
curl -s -X POST -H "Authorization: token $TOKEN" \
-H "Content-Type: application/json" \
"$GITEA_URL/api/v1/orgs/$ORG/repos" \
-d "$repo_json" | jq '{name: .full_name, url: .clone_url}'
done
7.6.2 权限审计脚本
#!/bin/bash
# audit-permissions.sh
GITEA_URL="https://git.example.com"
TOKEN="your_admin_token"
echo "=== 仓库权限审计 ==="
echo ""
# 获取所有组织
orgs=$(curl -s -H "Authorization: token $TOKEN" \
"$GITEA_URL/api/v1/orgs?limit=50" | jq -r '.[].username')
for org in $orgs; do
echo "--- Organization: $org ---"
# 获取组织团队
teams=$(curl -s -H "Authorization: token $TOKEN" \
"$GITEA_URL/api/v1/orgs/$org/teams" | jq -r '.[].name')
for team in $teams; do
# 获取团队成员
members=$(curl -s -H "Authorization: token $TOKEN" \
"$GITEA_URL/api/v1/orgs/$org/teams/$team/members" | jq -r '.[].login')
# 获取团队权限
permission=$(curl -s -H "Authorization: token $TOKEN" \
"$GITEA_URL/api/v1/orgs/$org/teams/$team" | jq -r '.permission')
printf " Team: %-20s Permission: %-10s Members: %s\n" \
"$team" "$permission" "$(echo $members | tr '\n' ', ')"
done
echo ""
done
7.7 扩展阅读
本章小结
| 学到了什么 | 关键要点 |
|---|---|
| 组织模型 | 按部门/产品/服务划分,选择适合团队的模型 |
| 权限继承 | 上级权限自动继承到下级,有效权限取最高值 |
| 分支保护 | main/develop 严格保护,feature 宽松 |
| 模板管理 | 使用模板仓库统一项目结构和配置 |
| 批量管理 | API + 脚本实现批量创建和审计 |
下一章:第 8 章 - 服务端钩子 — 利用 Git 钩子实现推送检查、自动部署和通知。