🌟 一、 场景背景与方案选择

问题场景:

  • 主仓库: 存放于公网/外网(如 Gitee),主要用于文档维护。
  • 子仓库(Demo): 存放于内网(如 GitLab),由各业务线独立管理。
  • 核心痛点: 既要在主仓库中展示特定版本的 Demo 代码,又要解决外网无法直接 clone 内网子模块(Submodule)的网络隔离问题。同时,代码审查通过 Gerrit 进行,所有提交必须附带 Change-Id。

最终方案:****git subtree + --squash

  • 为什么不用 Submodule? Submodule 仅记录指针,外部人员克隆主仓库时会因为连不上内网 GitLab 而拉取失败。
  • Subtree 的优势: 直接将内网 Demo 的物理代码拉取并随主仓库提交,跨越网络隔离。
  • --squash 的作用: 将子仓库杂乱的历史记录压缩成单条记录,保持主文档仓库的 Git 历史纯净。
    git subtree add 之后的 git log 样例

🚀 二、 核心操作:引入子仓库代码

1. 避坑前提:千万不要手动 clone!

在使用 git subtree add 之前,绝对不能提前手动去 git clone 子仓库。subtree add 命令本身自带拉取并创建目录的功能。如果目录已存在,Git 会报错:

❌ fatal: prefix 'xxx' already exists.

2. 执行引入命令

在主仓库根目录下,分别引入两个 Demo 仓库(假设放到 thirdparty/... 路径下):

# 引入第一个 demo
git subtree add --prefix=thirdparty/skysi/use_cases/kylin-v10-digitalme-docker git@192.168.1.18:penguido/kylin-v10-digitalme-docker.git master --squash

# 引入第二个 demo
git subtree add --prefix=thirdparty/skysi/use_cases/mt-docker git@192.168.1.18:penguido/mt-docker.git master --squash

💡 原理解析: 执行完毕后,git status 会显示 working tree clean。这是因为 Git 在后台已经自动为你完成了 4 次 Commit(每个子仓库产生 1 个 Squash Commit 提取代码 + 1 个 Merge Commit 合并到主分支)。


🛠️ 三、 push 一个干净的 commit log 给 gerrit

  1. git reset --soft <git subtree add 前的 commit id>

  2. git commit -m <请输入 commit 说明>

  3. 推送到 gerrit

    git push origin HEAD:refs/for/skysi

至此,干净的 commit 进入 Gerrit 代码审查流程!✅


💣 四、 踩坑实录与急救指南

坑点 1:git rebase 由 git subtree add --squash 添加的 commit

笔者这样尝试之后遇到了复杂的合并步骤处理,涉及 merge 的 commit 等笔者不熟悉的情况,暂不推荐。

回退命令:git rebase --abort

坑点 2:git rebase 期间不小心推送到了 gerrit ,即使在 gerrit 上 abandon ,审核员的合并也会失败

解决办法:将最终需要的 commit 变基到远程 skysi 分支的最新提交上。以笔者要推送到的 skysi 分支为例

  1. 查看当前提交历史确认
    git log --oneline -5

  2. 变基,将原来的父提交从"废弃的change"改为"skysi分支当前最新的正常提交"

    git fetch origin skysi
    git rebase --onto origin/skysi HEAD~1
    
  3. 强制推送更新 Gerrit(保持同一 Change-Id,但更新父提交)
    git push origin HEAD:refs/for/skysi

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐