multi-repo-git-ops
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseMulti-Repo Git Operations
多仓库Git操作
This skill handles git operations in multi-repo systems that use git submodules. The parent repo orchestrates multiple service repos, each an independent git repository with its own branches, history, and CI/CD.
Understanding this structure is essential — git operations here always involve deciding which repos are affected and operating in each one correctly.
本技能处理使用git子模块的多仓库系统中的git操作。父仓库协调管理多个服务仓库,每个服务仓库都是独立的git仓库,拥有自己的分支、提交历史和CI/CD。
理解该结构至关重要——此处的git操作始终需要先确定哪些仓库受影响,并在每个仓库中正确执行操作。
Discovery Protocol
发现协议
Before performing any git operations, discover the project structure dynamically. Never assume service names, branch mappings, or directory layout — always read from .
.gitmodules执行任何git操作前,先动态探查项目结构。永远不要假设服务名称、分支映射或目录布局——始终从文件中读取配置。
.gitmodulesStep 1: Identify submodules and their paths
步骤1:识别子模块及其路径
bash
undefinedbash
undefinedList all submodules with their paths
列出所有子模块及其路径
git config -f .gitmodules --get-regexp '.path$'
undefinedgit config -f .gitmodules --get-regexp '.path$'
undefinedStep 2: Identify each submodule's tracked branch
步骤2:识别每个子模块的跟踪分支
bash
undefinedbash
undefinedList all submodule branch mappings
列出所有子模块的分支映射
git config -f .gitmodules --get-regexp '.branch$'
git config -f .gitmodules --get-regexp '.branch$'
Get a specific service's default branch
获取特定服务的默认分支
git config -f .gitmodules submodule."{submodule-path}".branch
If a submodule has no branch configured in `.gitmodules`, check the remote:
```bash
cd {submodule-path}
git remote show origin | grep 'HEAD branch'git config -f .gitmodules submodule."{submodule-path}".branch
如果子模块未在`.gitmodules`中配置分支,则检查远程仓库:
```bash
cd {submodule-path}
git remote show origin | grep 'HEAD branch'Step 3: Detect project methodology
步骤3:检测项目方法论
- BMAD: Check if directory exists
_bmad-output/implementation-artifacts/ - If BMAD is detected, the BMAD Integration section applies
- BMAD:检查是否存在目录
_bmad-output/implementation-artifacts/ - 如果检测到BMAD,则适用BMAD集成部分的规则
Step 4: Cache discovered info for the session
步骤4:在会话中缓存探查得到的信息
After discovery, the agent knows:
- All submodule names and paths
- Each submodule's default branch
- Whether BMAD is in use
- The submodule directory prefix (commonly )
services/
Use this cached information for all subsequent operations in the session.
探查完成后,Agent将知晓:
- 所有子模块名称和路径
- 每个子模块的默认分支
- 是否使用BMAD
- 子模块目录前缀(通常为)
services/
会话中所有后续操作都将使用该缓存信息。
Repository Structure
仓库结构
A typical multi-repo project looks like this:
{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)Key principle: The parent repo tracks commit pointers to each submodule, not the submodule code itself. When you change code in a service, you commit in the service repo, then update the parent's pointer.
典型的多仓库项目结构如下:
{parent-repo}/ (父仓库——仅用于规划和协调)
├── .gitmodules (子模块定义及跟踪分支配置)
├── services/ (子模块仓库——目录名称可能不同)
│ ├── auth-service/ (分支: develop)
│ ├── booking-service/ (分支: dev)
│ ├── config-repo/ (分支: main)
│ └── ...
└── [项目方法论目录] (例如,使用BMAD时的 _bmad-output/)核心原则:父仓库跟踪每个子模块的提交指针,而非子模块的代码本身。当你修改服务中的代码时,先在服务仓库提交,再更新父仓库的指针。
Branch Conventions
分支规范
Default Branches by Service
各服务的默认分支
Services may track different default branches — always look up the correct one before branching:
bash
undefined不同服务可能跟踪不同的默认分支——创建分支前务必查询正确的默认分支:
bash
undefinedGet a service's default branch (always use this — never assume)
获取服务的默认分支(始终使用该结果,永远不要假设)
git config -f .gitmodules submodule."{submodule-path}".branch
Different services in the same project often use different default branches (e.g., `develop`, `dev`, `main`). The only reliable source of truth is `.gitmodules`.git config -f .gitmodules submodule."{submodule-path}".branch
同一项目中的不同服务通常使用不同的默认分支(例如`develop`、`dev`、`main`)。唯一可靠的信息来源是`.gitmodules`文件。Feature Branch Naming
特性分支命名
For ticket-based work (JIRA/project tracker):
{type}/{TICKET-ID}-{short-description}Examples: ,
feat/PROJ-1234-add-search-by-datebugfix/PROJ-5678-fix-null-pointerFor BMAD story work (derived from story file name):
feat/{story-key}The story key comes from the story file name. A story file named (representing Epic 1, Story 2) produces branch name .
1-2-user-authentication.mdfeat/1-2-user-authenticationBranch type prefixes: , , , ,
feat/fix/bugfix/chore/base/基于工单的工作(JIRA/项目跟踪工具):
{type}/{TICKET-ID}-{short-description}示例:、
feat/PROJ-1234-add-search-by-datebugfix/PROJ-5678-fix-null-pointerBMAD故事工作(从故事文件名派生):
feat/{story-key}故事键来自故事文件名。名为的故事文件(代表第1个史诗,第2个故事)对应的分支名为。
1-2-user-authentication.mdfeat/1-2-user-authentication分支类型前缀:、、、、
feat/fix/bugfix/chore/base/BMAD Integration (If Applicable)
BMAD集成(如适用)
This section applies only if the project uses the BMAD methodology. Detect this by checking for the directory.
_bmad-output/implementation-artifacts/BMAD manages work through story files and sprint status tracking. This section explains how git operations map to the BMAD lifecycle.
本部分仅适用于使用BMAD方法论的项目,可通过检查目录是否存在来检测。
_bmad-output/implementation-artifacts/BMAD通过故事文件和冲刺状态跟踪来管理工作,本部分说明git操作如何对应BMAD生命周期。
How Stories Reference Services
故事如何关联服务
BMAD story files live at . Stories reference affected services in several ways — check all of these:
_bmad-output/implementation-artifacts/{story-key}.md- Service tags in story title or body: ,
[auth-service][scheduler-service] - Dev Notes section: Lists "Source tree components to touch" with service paths
- Project Structure Notes: References paths like
services/{service-name}/src/... - Tasks/Subtasks: Individual tasks may reference different services
When a story doesn't explicitly tag services, look at the file paths mentioned in Dev Notes and Tasks to determine which submodule directories are involved.
BMAD故事文件存放在。故事通过多种方式关联受影响的服务,请检查所有以下项:
_bmad-output/implementation-artifacts/{story-key}.md- 故事标题或正文中的服务标签:、
[auth-service][scheduler-service] - 开发笔记部分:列出「需要修改的源码树组件」及服务路径
- 项目结构说明:引用类似的路径
services/{service-name}/src/... - 任务/子任务:单个任务可能引用不同的服务
当故事未明确标记服务时,查看开发笔记和任务中提到的文件路径,以确定涉及哪些子模块目录。
BMAD Status and Git Operations Mapping
BMAD状态与Git操作映射
BMAD tracks story status in . Each status transition has corresponding git operations:
_bmad-output/implementation-artifacts/sprint-status.yaml| Story Status Change | Git Operations Required |
|---|---|
| No git ops (story file creation only) |
| Create feature branches in affected services |
| Commit changes in service repos |
| Push all service branches, ensure clean state |
| Continue on same branches, commit fixes |
| PRs merged, update parent submodule pointers |
BMAD在中跟踪故事状态,每个状态转换都有对应的git操作:
_bmad-output/implementation-artifacts/sprint-status.yaml| 故事状态变更 | 所需Git操作 |
|---|---|
| 无git操作(仅创建故事文件) |
| 在受影响的服务中创建特性分支 |
| 在服务仓库中提交变更 |
| 推送所有服务分支,确保状态干净 |
| 在相同分支上继续工作,提交修复 |
| PR合并完成,更新父仓库的子模块指针 |
Starting a BMAD Story (Git Setup)
启动BMAD故事(Git配置)
When beginning work on a BMAD story, perform these git operations:
Step 1: Read the story and identify services
bash
undefined开始处理BMAD故事时,执行以下git操作:
步骤1:读取故事并识别服务
bash
undefinedStory files follow pattern: {epic_num}-{story_num}-{slug}.md
故事文件遵循格式:{epic_num}-{story_num}-{slug}.md
Example: _bmad-output/implementation-artifacts/1-2-user-authentication.md
示例:_bmad-output/implementation-artifacts/1-2-user-authentication.md
Read the story file. Extract affected services from:
- Service tags like `[auth-service]`
- File paths in Dev Notes (e.g., `services/{service-name}/src/...`)
- Task descriptions referencing specific services
**Step 2: Derive the branch name from the story key**
```bash
读取故事文件,从以下位置提取受影响的服务:
- 服务标签,如`[auth-service]`
- 开发笔记中的文件路径(例如`services/{service-name}/src/...`)
- 引用特定服务的任务描述
**步骤2:从故事键派生分支名**
```bashStory file: 1-2-user-authentication.md → branch: feat/1-2-user-authentication
故事文件:1-2-user-authentication.md → 分支:feat/1-2-user-authentication
STORY_KEY="1-2-user-authentication" # from the story file name (without .md)
BRANCH_NAME="feat/${STORY_KEY}"
**Step 3: Create branches in all affected services**
```bashSTORY_KEY="1-2-user-authentication" # 来自故事文件名(不含.md后缀)
BRANCH_NAME="feat/${STORY_KEY}"
**步骤3:在所有受影响的服务中创建分支**
```bashFor 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
Use the **same branch name** across all affected services for traceability. This makes it easy to find all changes related to a story across the system.
**Step 4: Verify setup**
```bashfor 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:验证配置**
```bashConfirm all affected services are on the correct branch
确认所有受影响的服务都在正确的分支上
git submodule foreach --quiet 'BRANCH=$(git branch --show-current); echo "$(basename $(pwd)): $BRANCH"'
undefinedgit submodule foreach --quiet 'BRANCH=$(git branch --show-current); echo "$(basename $(pwd)): $BRANCH"'
undefinedDuring Story Implementation
故事实现过程中
Committing changes — always commit inside the service directory:
bash
cd services/{service-name}
git add {specific-files}
git commit -m "feat({scope}): add validation for booking dates
Story: {story-key}"Working across multiple services — commit in each separately:
bash
undefined提交变更——始终在服务目录内提交:
bash
cd services/{service-name}
git add {specific-files}
git commit -m "feat({scope}): add validation for booking dates
Story: {story-key}"跨多个服务工作——分别在每个服务中提交:
bash
undefinedService A
服务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"
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
服务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"
All commits must follow the **Commit Message Format** section below — this is critical for release-please to generate correct changelogs and version bumps.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生成正确的变更日志和版本号至关重要。Completing a Story (Push & PR)
完成故事(推送与PR)
When story is ready for review:
Step 1: Run quality checks in each affected service
bash
cd services/{service-name}
npm run lint
npm run format
npm run typecheck
npm testStep 2: Push each service's feature branch
bash
undefined故事准备好评审时:
步骤1:在每个受影响的服务中运行质量检查
bash
cd services/{service-name}
npm run lint
npm run format
npm run typecheck
npm test步骤2:推送每个服务的特性分支
bash
undefinedPush services first — always before parent
先推送服务仓库——始终早于父仓库
cd services/{service-name}
git push origin feat/{story-key}
**Step 3: Create PR per service**
Each service gets its own PR: `feat/{story-key}` → service's default branch.
PR title format: `feat({story-key}): {story title}`
PR body should reference the story: `Story: {epic_num}.{story_num} - {title}`
**Step 4: After PRs are merged, update parent**
```bashcd 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合并后更新父仓库**
```bashFor each merged service:
对每个已合并的服务:
cd services/{service-name}
git checkout {default-branch}
git pull origin {default-branch}
cd ../..
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"
undefinedgit add services/auth-service services/bff-service
git commit -m "chore: update submodule pointers after story {story-key}
Services updated:
- auth-service
- bff-service"
undefinedCommit Message Format (Release-Please Compatible)
提交信息格式(兼容Release-Please)
If the project uses release-please for automated versioning and changelog generation, every commit message must follow the Conventional Commits specification so release-please can correctly determine version bumps and produce meaningful changelogs.
Even without release-please, Conventional Commits is the recommended format for multi-repo systems because it produces clean, parseable git history across many repositories.
如果项目使用release-please实现自动化版本管理和变更日志生成,每条提交信息必须遵循Conventional Commits规范,以便release-please正确判断版本升级幅度并生成有意义的变更日志。
即使不使用release-please,Conventional Commits也是多仓库系统的推荐格式,因为它能在多个仓库中生成清晰、可解析的git历史。
No AI Co-Author Trailers
禁止AI共同作者尾部信息
NEVER add trailers for AI agents in commit messages. This means no lines like:
Co-Authored-ByCo-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>Commit messages must only contain the conventional commit structure described below. AI attribution in commits pollutes changelogs, adds noise to git history, and provides no value. This rule applies to all commits — feature, fix, chore, or otherwise.
永远不要在提交信息中添加AI Agent的尾部信息,即不要出现如下内容:
Co-Authored-ByCo-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>提交信息必须仅包含下文描述的约定式提交结构。提交中的AI属性会污染变更日志,为git历史增加无用信息,没有任何价值。该规则适用于所有提交——特性、修复、日常维护等所有类型。
Structure
结构
<type>(<scope>): <description>
[optional body]
[optional footer(s)]Header rules:
- — required (see type table below)
type - — optional, a noun describing the affected code section in parentheses
scope - — required, immediately after
description:- Use imperative, present tense: "add" not "added" or "adds"
- Do not capitalize the first letter
- Do not end with a period
- Keep under ~100 characters
Body — optional, separated from header by a blank line. Free-form, explains the "what" and "why".
Footer(s) — optional, separated from body by a blank line. Used for breaking changes, story references, and other metadata.
<type>(<scope>): <description>
[optional body]
[optional footer(s)]头部规则:
- — 必填(参见下方类型表)
type - — 可选,括号内为描述受影响代码区域的名词
scope - — 必填,紧跟在
description之后:- 使用祈使句、现在时:用「add」而非「added」或「adds」
- 首字母不要大写
- 不要以句号结尾
- 长度控制在约100字符以内
正文 — 可选,与头部之间空一行。自由格式,说明变更的「内容」和「原因」。
尾部信息 — 可选,与正文之间空一行。用于说明破坏性变更、故事引用及其他元数据。
Commit Types and Version Bumps
提交类型与版本升级
Release-please only creates a release when it detects releasable units — commits with types that map to a version bump. Choosing the right type matters because it directly controls what version gets released and what appears in the changelog.
Release-please仅在检测到可发布单元——即提交类型对应版本升级时才会创建发布。选择正确的类型非常重要,因为它直接控制发布的版本号以及变更日志中显示的内容。
Releasable types (trigger a release)
可发布类型(触发发布)
| Type | SemVer Bump | When to use |
|---|---|---|
| Minor (0.x.0) | New capability, endpoint, feature, UI component |
| Patch (0.0.x) | Bug fix for existing functionality |
| Patch (0.0.x) | Dependency updates (package.json, lock files) |
| 类型 | SemVer升级幅度 | 使用场景 |
|---|---|---|
| 次版本 (0.x.0) | 新增功能、接口、特性、UI组件 |
| 修订版本 (0.0.x) | 修复现有功能的bug |
| 修订版本 (0.0.x) | 依赖更新(package.json、锁文件) |
Non-releasable types (won't trigger a release alone)
不可发布类型(不会单独触发发布)
| Type | When to use |
|---|---|
| Code restructuring without behavior change |
| Performance improvement (special refactoring) |
| Adding or correcting tests |
| Documentation changes only |
| Code style (formatting, whitespace, semicolons) |
| Maintenance tasks (.gitignore, configs, tooling) |
| Build system, dependencies, project version |
| CI/CD pipeline and workflow changes |
If you only commit non-releasable types since the last release, no release PR will be created. Be intentional — don't use when the change is actually a or .
chore:feat:fix:| 类型 | 使用场景 |
|---|---|
| 代码重构,无行为变更 |
| 性能优化(特殊的重构) |
| 添加或修正测试 |
| 仅文档变更 |
| 代码风格(格式、空格、分号) |
| 维护任务(.gitignore、配置、工具) |
| 构建系统、依赖、项目版本 |
| CI/CD流水线和工作流变更 |
如果自上次发布以来仅提交了不可发布类型的内容,则不会创建发布PR。请有意识地选择类型——如果变更实际是或,不要使用。
feat:fix:chore:Choosing the right type
选择正确的类型
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新增功能或特性? → feat
修复bug? → fix
依赖更新? → deps
性能优化? → perf
代码重构,无行为变更? → refactor
仅文档变更? → docs
仅测试变更? → test
CI/CD或构建变更? → ci / build
其他所有情况(配置、工具)?→ choreBreaking Changes (Major Bump)
破坏性变更(主版本升级)
Any commit type with a breaking change triggers a major version bump. Two formats:
Option A — in the header:
!feat(api)!: redesign authentication flow
BREAKING CHANGE: the /auth/login endpoint now requires OAuth2 tokens
instead of API keys. All existing integrations must migrate.Option B — footer only:
refactor(database): migrate from MongoDB to PostgreSQL
BREAKING CHANGE: all database connection strings must be updated.
The MongoDB driver is no longer included.Both (space) and (hyphen) are recognized in footers.
BREAKING CHANGEBREAKING-CHANGEWhen marking a breaking change, always include a footer explaining the migration impact — even when using the format. The footer is what consumers read to understand what they need to change.
BREAKING CHANGE:!任何包含破坏性变更的提交类型都会触发主版本升级,有两种格式:
选项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 CHANGEBREAKING-CHANGE标记破坏性变更时,始终添加尾部信息说明迁移影响——即使使用了格式。尾部信息是用户了解需要修改哪些内容的依据。
BREAKING CHANGE:!Scopes
范围
Scopes describe which code section is affected — they help organize changelogs and, in monorepo setups, route changes to the correct package.
Good scopes (describe code areas):
feat(auth): add JWT validation
fix(scheduler): correct cron expression parsing
refactor(booking): extract date utilityBad scopes (these are anti-patterns):
fix(PROJ-1234): ... ← ticket IDs are not scopes
feat(john): ... ← people are not scopesUse the domain or module name as the scope (e.g., , , , , , ).
authbookingschedulermiddlewareconfigmigration范围描述受影响的代码区域——有助于组织变更日志,在monorepo配置中可将变更路由到正确的包。
好的范围示例(描述代码区域):
feat(auth): add JWT validation
fix(scheduler): correct cron expression parsing
refactor(booking): extract date utility不好的范围示例(反模式):
fix(PROJ-1234): ... ← 工单ID不是范围
feat(john): ... ← 人员不是范围使用领域或模块名称作为范围(例如、、、、、)。
authbookingschedulermiddlewareconfigmigrationStory References
故事引用
If using BMAD, include the story key in the commit body or footer, not in the scope:
feat(auth): add JWT validation endpoint
Implement token validation with RS256 signing.
Story: 1-2-user-authentication如果使用BMAD,将故事键添加到提交的正文或尾部,不要放在范围中:
feat(auth): add JWT validation endpoint
Implement token validation with RS256 signing.
Story: 1-2-user-authenticationSpecial Release-Please Footers
特殊Release-Please尾部信息
| Footer | Purpose |
|---|---|
| Triggers major version bump |
| Force a specific version number |
Release-Aschore: prepare v3.0.0 release
Release-As: 3.0.0| 尾部信息 | 用途 |
|---|---|
| 触发主版本升级 |
| 强制使用指定的版本号 |
Release-Aschore: prepare v3.0.0 release
Release-As: 3.0.0Complete Examples
完整示例
Simple feature (minor bump):
feat(booking): add search by date range endpointBug fix with context (patch bump):
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-improvementsBreaking change (major bump):
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-migrationDependency update (patch bump):
deps: upgrade @nestjs/core to v11.0.0Test-only change (no release):
test(scheduler): add unit tests for cron expression parserChore (no release):
chore: update .gitignore to exclude coverage reports简单特性(次版本升级):
feat(booking): add search by date range endpoint带上下文的bug修复(修订版本升级):
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 reportsParent Repo Commit Messages
父仓库提交信息
When updating submodule pointers in the parent repo, use since these don't represent feature changes in the parent itself:
chore:chore: update submodule pointers after story 1-2-user-authentication
Services updated:
- auth-service
- bff-service在父仓库中更新子模块指针时,使用类型,因为这些变更不代表父仓库本身的功能变更:
chore:chore: update submodule pointers after story 1-2-user-authentication
Services updated:
- auth-service
- bff-serviceGeneral Operations Reference
通用操作参考
Create Feature Branch (Non-BMAD)
创建特性分支(非BMAD场景)
For ad-hoc work not tied to a BMAD story:
bash
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}适用于不关联BMAD故事的临时工作:
bash
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}Sync All Submodules
同步所有子模块
bash
undefinedbash
undefinedPull parent and update all submodule pointers
拉取父仓库更新并更新所有子模块指针
git pull origin main
git submodule update --recursive
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)'
undefinedgit submodule foreach 'git pull origin $(git config -f $toplevel/.gitmodules submodule.$name.branch)'
undefinedCheck Status Across All Repos
检查所有仓库的状态
bash
undefinedbash
undefinedQuick 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'
'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'
undefinedgit 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'
'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'
undefinedSwitch Service Back to Default Branch
将服务切回默认分支
bash
DEFAULT_BRANCH=$(git config -f .gitmodules submodule."{submodule-path}".branch)
cd {submodule-path}
git checkout $DEFAULT_BRANCH
git pull origin $DEFAULT_BRANCHbash
DEFAULT_BRANCH=$(git config -f .gitmodules submodule."{submodule-path}".branch)
cd {submodule-path}
git checkout $DEFAULT_BRANCH
git pull origin $DEFAULT_BRANCHCI/CD Awareness
CI/CD注意事项
Understanding what happens when you push is critical in multi-repo systems. Typical branch-to-deployment mappings:
| Branch | Typical Push Effect |
|---|---|
| May auto-deploy to dev environment — confirm with user first |
| Stable reference — deployment workflows available |
| Manual deployment via |
| CI runs (lint, test, build) but no deployment |
Actual deployment behavior depends on the project's CI/CD configuration. Check if the project has a shared CI/CD workflow repository among its submodules, and confirm with the user which branches trigger deployments.
在多仓库系统中,了解推送后会发生什么至关重要。典型的分支-部署映射关系:
| 分支 | 典型推送效果 |
|---|---|
| 可能自动部署到开发环境——先与用户确认 |
| 稳定参考分支——有部署工作流可用 |
| 通过 |
| 运行CI(检查、测试、构建)但不部署 |
实际部署行为取决于项目的CI/CD配置。检查项目的子模块中是否有共享的CI/CD工作流仓库,并与用户确认哪些分支会触发部署。
Safety Rules
安全规则
These rules prevent common mistakes in multi-repo systems:
- Always push service repos before parent — pushing parent first creates broken submodule pointers that break other developers' checkouts
- Never force-push to shared default branches (,
develop,dev) — these are shared branchesmain - Confirm with user before pushing to deployment-triggering branches
- Check service's default branch before creating feature branches — they differ across services, and branching from the wrong base causes merge conflicts
- Never use or
git add .in service repos — always add specific files to avoid committing secrets or build artifactsgit add -A - Never commit , credentials, secrets, or
.envin any reponode_modules - Same branch name across services for multi-service stories — enables traceability
- Update sprint-status.yaml when git operations change story state (branch created → , pushed for review →
in-progress) — only if using BMADreview - Never add trailers for AI agents in commit messages — no Claude, Copilot, or any AI attribution. These pollute changelogs and git history. Commit messages must contain only the conventional commit structure (type, scope, description, body, footers for breaking changes/story refs)
Co-Authored-By - All commit messages must be Conventional Commits format — release-please depends on this for automated versioning and changelog generation. A malformed commit message can cause missed releases or incorrect version bumps
这些规则可避免多仓库系统中的常见错误:
- 始终先推送服务仓库,再推送父仓库——先推送父仓库会创建损坏的子模块指针,影响其他开发者的 checkout
- 永远不要强制推送到共享的默认分支(、
develop、dev)——这些是共享分支main - 推送到会触发部署的分支前与用户确认
- 创建特性分支前检查服务的默认分支——不同服务的默认分支不同,从错误的基础分支创建会导致合并冲突
- 在服务仓库中永远不要使用或
git add .——始终添加指定文件,避免提交密钥或构建产物git add -A - 任何仓库中永远不要提交、凭证、密钥或
.envnode_modules - 多服务故事在所有服务中使用相同的分支名——便于追溯
- 当git操作变更故事状态时更新sprint-status.yaml(分支创建→,推送评审→
in-progress)——仅使用BMAD时适用review - 提交信息中永远不要添加AI Agent的尾部信息——不要添加Claude、Copilot或任何AI属性,这些会污染变更日志和git历史。提交信息必须仅包含约定式提交结构(类型、范围、描述、正文、破坏性变更/故事引用的尾部信息)
Co-Authored-By - 所有提交信息必须遵循Conventional Commits格式——release-please依赖该格式实现自动化版本管理和变更日志生成。格式错误的提交信息会导致发布遗漏或版本升级错误