mcpField
M
multi-repo-git-ops

multi-repo-git-ops

github.com/bmad-labs开发1995 次安装6 天前更新
代码仓库

关于 multi-repo-git-ops

multi-repo-git-ops 是一项面向由父仓库和 Git 子模块组成项目的技能。它指导 Agent 发现仓库结构、管理各服务的分支与提交,并在适用时配合 BMAD 故事流程。

主要功能

  1. 01发现子模块及其跟踪分支
  2. 02将改动映射到相关仓库
  3. 03协调多个服务的分支
  4. 04指导提交、推送与拉取请求
  5. 05按 BMAD 故事安排 Git 操作

适用场景

  1. 01启动跨多个服务仓库的工作
  2. 02实现涉及多个服务的 BMAD 故事
  3. 03准备服务改动以供审查和合并

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/bmad-labs/skills --skill multi-repo-git-ops

安装后在 Claude Code 中输入/multi-repo-git-ops确认已加载。

详细介绍

多仓库 Git 操作

此技能用于处理使用 Git 子模块的多仓库系统中的 Git 操作。父仓库负责协调多个服务仓库,每个服务仓库都是独立的 Git 仓库,拥有自己的分支、历史记录和 CI/CD。

理解这一结构至关重要——这里的 Git 操作始终需要先确定哪些仓库会受到影响,再在每个仓库中正确执行操作。

发现流程

执行任何 Git 操作之前,都要动态发现项目结构。切勿假设服务名称、分支映射或目录布局——始终从 .gitmodules 读取。

步骤 1:识别子模块及其路径
# List all submodules with their paths
git config -f .gitmodules --get-regexp '\.path$'
步骤 2:识别每个子模块所跟踪的分支
# List all submodule branch mappings
git config -f .gitmodules --get-regexp '\.branch$'

# Get a specific service's default branch
git config -f .gitmodules submodule."{submodule-path}".branch

如果 .gitmodules 中未为某个子模块配置分支,请检查远程:

cd {submodule-path}
git remote show origin | grep 'HEAD branch'
步骤 3:检测项目方法论
  • BMAD:检查 _bmad-output/implementation-artifacts/ 目录是否存在
  • 如果检测到 BMAD,则适用 BMAD 集成部分
步骤 4:缓存本次会话中发现的信息

发现后,Agent 将了解:

  • 所有子模块的名称和路径
  • 每个子模块的默认分支
  • 是否使用 BMAD
  • 子模块目录前缀(通常为 services/)

在本次会话后续的所有操作中使用这些缓存信息。

仓库结构

典型的多仓库项目如下所示:

{parent-repo}/                       (parent repo — planning & orchestration only)
├── .gitmodules                      (submodule definitions with tracked branches)
├── services/                        (submodule repos — directory name may vary)
│   ├── auth-service/                (branch: develop)
│   ├── booking-service/             (branch: dev)
│   ├── config-repo/                 (branch: main)
│   └── ...
└── [project methodology dirs]       (e.g., _bmad-output/ if using BMAD)

关键原则:父仓库跟踪的是每个子模块的提交指针,而不是子模块代码本身。修改服务中的代码时,应先在服务仓库中提交,然后更新父仓库中的指针。

分支约定

各服务的默认分支

服务可能跟踪不同的默认分支——创建分支之前,始终先查明正确的默认分支:

# Get a service's default branch (always use this — never assume)
git config -f .gitmodules submodule."{submodule-path}".branch

同一项目中的不同服务通常使用不同的默认分支(例如 develop、dev、main)。.gitmodules 是唯一可靠的信息来源。

功能分支命名

对于基于工单的工作(JIRA/项目跟踪工具):

{type}/{TICKET-ID}-{short-description}

示例:feat/PROJ-1234-add-search-by-date、bugfix/PROJ-5678-fix-null-pointer

对于 BMAD 故事相关工作(根据故事文件名生成):

feat/{story-key}

故事键取自故事文件名。名为 1-2-user-authentication.md 的故事文件(表示 Epic 1、Story 2)会生成分支名 feat/1-2-user-authentication。

分支类型前缀:feat/、fix/、bugfix/、chore/、base/

BMAD 集成(如适用)

本部分仅适用于使用 BMAD 方法论的项目。通过检查 _bmad-output/implementation-artifacts/ 目录来进行检测。

BMAD 通过故事文件和冲刺状态跟踪来管理工作。本部分介绍 Git 操作如何对应 BMAD 生命周期。

故事如何引用服务

BMAD 故事文件位于 _bmad-output/implementation-artifacts/{story-key}.md。故事会通过多种方式引用受影响的服务——请检查以下所有位置:

  1. 故事标题或正文中的服务标签:[auth-service]、[scheduler-service]
  2. Dev Notes 部分:列出“要修改的源代码树组件”及其服务路径
  3. Project Structure Notes:引用 services/{service-name}/src/... 等路径
  4. Tasks/Subtasks:各个任务可能会引用不同的服务

当故事未明确标注服务时,请查看 Dev Notes 和 Tasks 中提到的文件路径,以确定涉及哪些子模块目录。

BMAD 状态与 Git 操作映射

BMAD 会在 _bmad-output/implementation-artifacts/sprint-status.yaml 中跟踪故事状态。每次状态转换都有对应的 Git 操作:

故事状态变更所需的 Git 操作
backlog → ready-for-dev无需 Git 操作(仅创建故事文件)
ready-for-dev → in-progress在受影响的服务中创建功能分支
in-progress(持续进行中)在服务仓库中提交更改
in-progress → review推送所有服务分支,确保工作区干净
review → in-progress(修复)继续使用相同分支,并提交修复
review → donePR 已合并,更新父级子模块指针
开始 BMAD 故事(Git 设置)

开始处理 BMAD 故事时,请执行以下 Git 操作:

步骤 1:阅读故事并确定涉及的服务

# Story files follow pattern: {epic_num}-{story_num}-{slug}.md
# Example: _bmad-output/implementation-artifacts/1-2-user-authentication.md

阅读故事文件。从以下内容中提取受影响的服务:

  • 服务标签,例如 [auth-service]
  • Dev Notes 中的文件路径(例如 services/{service-name}/src/...)
  • 提及特定服务的任务描述

步骤 2:根据故事键生成分支名称

# Story file: 1-2-user-authentication.md → branch: feat/1-2-user-authentication
STORY_KEY="1-2-user-authentication"  # from the story file name (without .md)
BRANCH_NAME="feat/${STORY_KEY}"

步骤 3:在所有受影响的服务中创建分支

# For each affected service (replace with actual discovered service names):
for SERVICE in auth-service scheduler-service; do
  DEFAULT_BRANCH=$(git config -f .gitmodules submodule."services/$SERVICE".branch)
  cd services/$SERVICE
  git checkout $DEFAULT_BRANCH
  git pull origin $DEFAULT_BRANCH
  git checkout -b $BRANCH_NAME
  git push -u origin $BRANCH_NAME
  cd ../..
done

在所有受影响的服务中使用相同的分支名称,以便追踪。这样就能轻松找到系统中与某个故事相关的所有更改。

步骤 4:验证设置

# Confirm all affected services are on the correct branch
git submodule foreach --quiet 'BRANCH=$(git branch --show-current); echo "$(basename $(pwd)): $BRANCH"'
故事实施期间

提交更改——始终在服务目录中提交:

cd services/{service-name}
git add {specific-files}
git commit -m "feat({scope}): add validation for booking dates

Story: {story-key}"

跨多个服务协作——分别在每个服务中提交:

# Service A
cd services/auth-service
git add src/auth/jwt.service.ts src/auth/jwt.service.spec.ts
git commit -m "feat(auth): add JWT validation endpoint

Story: 1-2-user-authentication"

# Service B
cd ../bff-service
git add src/middleware/auth.middleware.ts
git commit -m "feat(middleware): add JWT auth middleware

Story: 1-2-user-authentication"

所有提交都必须遵循下文的提交消息格式部分——这对 release-please 正确生成变更日志和版本升级至关重要。

完成故事(推送与 PR)

故事准备好接受审查时:

步骤 1:在每个受影响的服务中运行质量检查

cd services/{service-name}
npm run lint
npm run format
npm run typecheck
npm test

步骤 2:推送每个服务的功能分支

# Push services first — always before parent
cd services/{service-name}
git push origin feat/{story-key}

步骤 3:为每个服务创建 PR 每个服务都需要单独的 PR:feat/{story-key} → 服务的默认分支。

PR 标题格式:feat({story-key}): {story title} PR 正文应引用故事:Story: {epic_num}.{story_num} - {title}

步骤 4:PR 合并后,更新父级

# For each merged service:
cd services/{service-name}
git checkout {default-branch}
git pull origin {default-branch}
cd ../..

# Update parent pointers (use actual discovered service paths)
git add services/auth-service services/bff-service
git commit -m "chore: update submodule pointers after story {story-key}

Services updated:
- auth-service
- bff-service"

提交消息格式(兼容 Release-Please)

如果项目使用 release-please 自动管理版本和生成变更日志,那么每条提交消息都必须遵循 Conventional Commits 规范,以便 release-please 正确确定版本升级并生成有意义的变更日志。

即使不使用 release-please,Conventional Commits 也是多仓库系统的推荐格式,因为它能在多个仓库中生成整洁、可解析的 Git 历史记录。

不要添加 AI 共同作者尾注

绝不要在提交消息中为 AI Agent 添加 Co-Authored-By 尾注。 这意味着不要添加如下行:

Co-Authored-By: Claude <[email protected]>
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

提交消息只能包含下文所述的 Conventional Commits 结构。在提交中标注 AI 归属会污染变更日志、给 Git 历史记录增加噪声,而且毫无价值。此规则适用于所有提交——功能、修复、杂项或其他类型。

结构
<type>(<scope>): <description>

[optional body]

[optional footer(s)]

标题规则:

  • type——必填(参见下方的类型表)
  • scope——可选,用括号括起,用于描述受影响代码部分的名词
  • description——必填,紧跟在 : 后
    • 使用祈使语气和现在时:“add”,而非“added”或“adds”
    • 首字母不要大写
    • 末尾不要加句号
    • 长度控制在约 100 个字符以内

正文——可选,与标题之间以空行分隔。自由格式,用于说明“做了什么”以及“为什么”。

页脚——可选,与正文之间以空行分隔。用于记录破坏性变更、故事引用及其他元数据。

提交类型与版本升级

Release-please 仅在检测到可发布单元时才会创建发布——也就是类型对应版本升级的提交。选择正确的类型很重要,因为它会直接决定发布的版本以及变更日志中的内容。

可发布类型(会触发发布)
类型SemVer 升级使用场景
feat次版本(0.x.0)新能力、端点、功能、UI 组件
fix修订版本(0.0.x)修复现有功能中的错误
deps修订版本(0.0.x)更新依赖项(package.json、锁定文件)
不可发布类型(单独使用时不会触发发布)
类型使用场景
refactor重构代码,但不改变行为
perf性能改进(特殊重构)
test添加或修正测试
docs仅修改文档
style代码风格(格式、空白、分号)
chore维护任务(.gitignore、配置、工具)
build构建系统、依赖项、项目版本
ciCI/CD 流水线和工作流变更

如果自上次发布以来只提交了不可发布类型,则不会创建发布 PR。请谨慎选择——如果变更实际属于 feat: 或 fix:,就不要使用 chore:。

选择正确的类型
New capability or feature?           → feat
Fixing a bug?                        → fix
Dependency update?                   → deps
Performance improvement?             → perf
Code restructuring, no behavior Δ?   → refactor
Documentation only?                  → docs
Tests only?                          → test
CI/CD or build changes?              → ci / build
Everything else (configs, tooling)?  → chore
重大变更(主版本升级)

任何类型的提交只要包含重大变更,都会触发主版本升级。格式有两种:

选项 A — 在标题中使用 !:

feat(api)!: redesign authentication flow

BREAKING CHANGE: the /auth/login endpoint now requires OAuth2 tokens
instead of API keys. All existing integrations must migrate.

选项 B — 仅使用页脚:

refactor(database): migrate from MongoDB to PostgreSQL

BREAKING CHANGE: all database connection strings must be updated.
The MongoDB driver is no longer included.

页脚中的 BREAKING CHANGE(空格)和 BREAKING-CHANGE(连字符)都会被识别。

标记重大变更时,务必添加 BREAKING CHANGE: 页脚,说明迁移影响——即使使用 ! 格式也一样。使用者会通过该页脚了解需要做哪些变更。

作用域

作用域用于说明受影响的代码部分——它有助于整理变更日志,并在单体仓库配置中将变更分配到正确的软件包。

好的作用域(描述代码区域):

feat(auth): add JWT validation
fix(scheduler): correct cron expression parsing
refactor(booking): extract date utility

不好的作用域(这些属于反模式):

fix(PROJ-1234): ...          ← ticket IDs are not scopes
feat(john): ...               ← people are not scopes

使用领域或模块名称作为作用域(例如,auth、booking、scheduler、middleware、config、migration)。

Story 引用

如果使用 BMAD,请将 Story 键放在提交正文或页脚中,而不是作用域中:

feat(auth): add JWT validation endpoint

Implement token validation with RS256 signing.

Story: 1-2-user-authentication
Release-Please 专用页脚
页脚用途
BREAKING CHANGE: <desc>触发主版本升级
Release-As: x.x.x强制指定版本号

Release-As 示例——适用于首次发布或协调版本跃迁:

chore: prepare v3.0.0 release

Release-As: 3.0.0
完整示例

简单功能(次版本升级):

feat(booking): add search by date range endpoint

附带上下文的错误修复(修订版本升级):

fix(auth): resolve token refresh race condition

The refresh token was being invalidated before the new access token
was issued, causing a brief window where requests would fail.

Story: 2-3-auth-improvements

重大变更(主版本升级):

feat(api)!: remove deprecated v1 booking endpoints

BREAKING CHANGE: all /api/v1/bookings/* endpoints are removed.
Consumers must migrate to /api/v2/bookings/* which uses the new
pagination format.

Story: 3-1-api-v2-migration

依赖项更新(修订版本升级):

deps: upgrade @nestjs/core to v11.0.0

仅修改测试(不发布):

test(scheduler): add unit tests for cron expression parser

维护任务(不发布):

chore: update .gitignore to exclude coverage reports
父仓库提交消息

在父仓库中更新子模块指针时,请使用 chore:,因为这些变更并不代表父仓库本身的功能变更:

chore: update submodule pointers after story 1-2-user-authentication

Services updated:
- auth-service
- bff-service

常规操作参考

创建功能分支(非 BMAD)

对于未关联 BMAD Story 的临时工作:

DEFAULT_BRANCH=$(git config -f .gitmodules submodule."{submodule-path}".branch)
cd {submodule-path}
git checkout $DEFAULT_BRANCH
git pull origin $DEFAULT_BRANCH
git checkout -b feat/{TICKET-ID}-{description}
git push -u origin feat/{TICKET-ID}-{description}
同步所有子模块
# Pull parent and update all submodule pointers
git pull origin main
git submodule update --recursive

# OR: Pull latest from each submodule's tracked branch
git submodule foreach 'git pull origin $(git config -f $toplevel/.gitmodules submodule.$name.branch)'
检查所有仓库的状态
# Quick status: show only services with changes or non-default branches
git submodule foreach --quiet \
  'STATUS=$(git status --porcelain); BRANCH=$(git branch --show-current); DEFAULT=$(git config -f $toplevel/.gitmodules submodule.$name.branch); if [ -n "$STATUS" ] || [ "$BRANCH" != "$DEFAULT" ]; then echo "$(basename $(pwd)) [$BRANCH]: $([ -n "$STATUS" ] && echo "has changes" || echo "clean, non-default branch")"; fi'
将服务切换回默认分支
DEFAULT_BRANCH=$(git config -f .gitmodules submodule."{submodule-path}".branch)
cd {submodule-path}
git checkout $DEFAULT_BRANCH
git pull origin $DEFAULT_BRANCH

CI/CD 感知

在多仓库系统中,了解推送后会发生什么至关重要。典型的分支与部署映射如下:

分支典型的推送效果
develop / dev可能会自动部署到开发环境——请先与用户确认
main稳定的参考分支——可使用部署工作流
test、stage、release通过 workflow_dispatch 手动部署
feat/*、base/*CI 会运行(lint、test、build),但不会部署

实际部署行为取决于项目的 CI/CD 配置。检查项目是否将共享 CI/CD 工作流仓库作为子模块,并与用户确认哪些分支会触发部署。

安全规则

这些规则可避免多仓库系统中的常见错误:

  1. 始终先推送服务仓库,再推送父仓库——先推送父仓库会创建损坏的子模块指针,导致其他开发者无法检出
  2. 绝不对共享的默认分支(develop、dev、main)执行强制推送——这些都是共享分支
  3. 推送到会触发部署的分支前,务必与用户确认
  4. 创建功能分支前,先检查服务的默认分支——不同服务的默认分支可能不同,从错误的基准分支创建分支会导致合并冲突
  5. 绝不要在服务仓库中使用 git add . 或 git add -A——始终添加指定文件,以避免提交密钥或构建产物
  6. 绝不要在任何仓库中提交 .env、凭据、密钥或 node_modules
  7. 多服务事项应在各服务中使用相同的分支名称——便于追踪
  8. 当 Git 操作改变事项状态时,更新 sprint-status.yaml(创建分支 → in-progress,推送供审核 → review)——仅限使用 BMAD 时
  9. 提交信息中绝不要添加 AI Agent 的 Co-Authored-By 尾注——不得注明 Claude、Copilot 或任何 AI 的参与。这类内容会污染变更日志和 Git 历史。提交信息只能包含约定式提交结构(类型、范围、描述、正文,以及用于注明破坏性变更/事项引用的页脚)
  10. 所有提交信息都必须采用 Conventional Commits 格式——release-please 依赖该格式来自动确定版本号并生成变更日志。格式错误的提交信息可能导致版本发布遗漏或版本号调整不正确

评论

支持 Markdown