不能直接在master上改定制需求,因为master是公共基线,所有定制分支(如beijing/v3.2、shanghai/v3.2)均从中派生;若在master中加入某渠道专属逻辑(如“北京政务版”登录页样式),该改动将被其他无关渠道自动继承,引发功能误生效、冲突频发或上线异常。

为什么不能直接在 master 上改定制需求
因为 master 是公共基线,所有定制分支都从中派生。一旦你在 master 上直接修改某个渠道专属逻辑(比如「北京政务版」的登录页样式),这些改动就会被其他渠道(如「上海政务版」「企业版」)自动继承——而它们根本不需要这个改动,甚至可能因此出错。git merge 或 git cherry-pick 时不会自动过滤掉渠道特有代码,只能靠人肉判断,极易漏合或误合。
常见错误现象:fatal: refusing to merge unrelated histories(强制合并两个无共同祖先的分支)、CONFLICT (content) 频繁出现在无关文件上、上线后发现 A 渠道功能在 B 渠道意外生效。
- master 只放真正通用的代码:核心框架、基础组件、跨渠道通用 bug 修复
- 每个定制渠道必须有独立分支,例如
beijing/v3.2、shanghai/v3.2、enterprise/v3.2 - 分支命名要带渠道标识和版本号,避免
feature/beijing-login这类临时名——它无法体现生命周期和归属
如何同步公共修复到所有定制分支
用 git cherry-pick 是最可控的方式,比 git merge 更精准,尤其适合只推送单次提交的 hotfix。
假设你在 origin/master 修复了一个登录态校验漏洞,提交 hash 是 a1b2c3d,需要同步到全部定制分支:
git checkout beijing/v3.2<br>git cherry-pick a1b2c3d<br>git push origin beijing/v3.2<br><br>git checkout shanghai/v3.2<br>git cherry-pick a1b2c3d<br>git push origin shanghai/v3.2
注意:如果某定制分支已自行实现过类似逻辑(比如自己重写了登录校验),cherry-pick 很可能触发冲突。这时不能跳过,必须手动检查逻辑是否重复、是否覆盖原有行为。
- 每次
cherry-pick后,务必在对应渠道的测试环境验证,不能只跑 CI - 避免批量
cherry-pick多个提交——不同提交之间可能有依赖,顺序错乱会导致编译失败或逻辑异常 - 记录同步日志:在内部 Wiki 或 PR 描述里写明「master commit a1b2c3d 已同步至 beijing/v3.2、shanghai/v3.2」
定制分支间代码复用该怎么处理
两个定制分支(如 beijing/v3.2 和 shanghai/v3.2)偶然出现相似需求(比如都需接入新的人脸识别 SDK),但又不值得上升到 master。这时候不该复制粘贴,也不该强行 merge,而是提取为「渠道共享分支」。
操作步骤:
git checkout -b shared/face-sdk-v1.0 beijing/v3.2<br># 实现 SDK 接入逻辑<br>git add . && git commit -m "feat: face SDK v1.0 integration"<br>git push origin shared/face-sdk-v1.0
然后分别在两个定制分支上合并该共享分支:
git checkout beijing/v3.2<br>git merge shared/face-sdk-v1.0<br><br>git checkout shanghai/v3.2<br>git merge shared/face-sdk-v1.0
这样既避免了代码散落,又保持了各渠道分支的独立演进路径。后续其他渠道要用,也只需 git merge 这个共享分支即可。
- 共享分支命名必须带明确作用域,如
shared/face-sdk-v1.0,而非shared/feature - 共享分支不直接推送生产,只作为中转;它本身不发版,也不接受来自定制分支的反向提交
- 如果共享逻辑后续需调整,应新建
shared/face-sdk-v1.1,而不是 amend 或 force-push 原分支
CI/CD 流水线怎么识别不同定制分支
构建脚本不能硬编码渠道名,得从 Git 分支名动态提取。例如在 GitHub Actions 或 GitLab CI 中,用 ${GITHUB_HEAD_REF} 或 $CI_COMMIT_REF_NAME 获取当前分支名,再用正则匹配渠道标识。
示例(GitHub Actions):
- name: Set channel<br> run: |<br> if [[ "${{ github.head_ref }}" =~ ^beijing/ ]]; then<br> echo "CHANNEL=beijing" >> $GITHUB_ENV<br> elif [[ "${{ github.head_ref }}" =~ ^shanghai/ ]]; then<br> echo "CHANNEL=shanghai" >> $GITHUB_ENV<br> fi
后续构建步骤就能基于 $CHANNEL 加载对应配置、资源包、签名证书。关键点是:分支名即渠道身份,不要额外维护映射表。
- 禁止在 CI 脚本里写死分支名,比如
if branch == 'beijing/v3.2'—— 新增渠道就得改脚本 - 远程分支名必须规范,否则正则会失效;建议用
^[a-z]+/[v0-9.]+$校验 - 构建产物包名应包含渠道信息,如
app-beijing-v3.2.1.apk,避免人工归档时混淆
实际落地中最容易被忽略的是分支生命周期管理:定制分支不是一次性的,它要随主干版本升级持续存在。比如 beijing/v3.2 未来要升到 beijing/v4.0,不是删旧建新,而是通过 git merge origin/main 拉入新基线后再适配——这个动作没人监督就容易断代。











