将已存在的git仓库移动到新建的父仓库下
还原当时情景🔄️
为了方便,库的名称就用仓库1,仓库2...命名了
我当时具有两个本地仓库仓库1,仓库2,并且都已经连接到了远程仓库。
由于在与 AI 讨论下一步开发规划的时候,我引用的是我两个仓库的父文件夹,所以 AI 提供的下一步规划中包含了我父文件夹的 README.md 等的内容。
由于本人具有一点点强迫症😶🌫️以及有亿点懒,综合考虑之下,AI 说什么就是什么吧,因此我就考虑该如何不重复提交很多代码的情况下创建一个父仓库
如果是直接创建一个父仓库并连接远程的话那就简单多了,但是我之前单独创建的那两个仓库有什么意义呢?
AI 娘神力
OK,遇事不决,AI 神力。我直接把疑问甩给了 AI,不得不说,确实好使,还有多种方案。这里我就直接仍方案对比了昂,毕竟每个方案的字数也不少( AI 可是不会省 TOKEN 的😶)
| 方案 | 保持独立 | 保留历史 | 克隆难度 | 适合场景 |
|---|---|---|---|---|
| A. Submodule | ✅ | ✅ | ⭐⭐ | 团队各自维护 |
| B. Subtree | ❌ | ✅ | ⭐ | 一个仓库管理所有 |
| C. 直接复制 | ❌ | ❌ | ⭐ | 历史不重要 |
然后鉴于我既要有要的想法,那当然是选择 A 方案喽
解决方案
现在的场景有个关键点:仓库1 和 仓库2 已经是完整的 git 仓库了,直接把它们作为 submodule 加进来,需要先把它们"挪出去"再添加
创建父仓库
登录你自己的 github ,然后创建一个父仓库,注意,不要勾选 "Add a README file" 和 ".gitignore"(保持空仓库) ,然后记住你的这个远程仓库的地址
https://github.com/你的用户名/父仓库.git
本地操作流程
-
进入父目录,初始化 git
git init -
将两个子仓库移动出去,因为 git submodule add 要求目标目录不存在或为空,最后父目录为空即可
-
添加两个子仓库为 submodule
用远程仓库的 URL(不是本地路径),这样别人克隆时才能拉到代码
git submodule add https://github.com/你的用户名/仓库1.git 仓库1
git submodule add https://github.com/你的用户名/仓库2.git 仓库2执行后:
-
会从远程仓库拉取 代码到本地对应目录
-
生成 .gitmodules 文件(记录两个子模块的 URL)
-
生成 .git/modules/ 目录(存 submodule 的元数据)
-
-
提交父仓库
git add .
git commit -m "初始化:引入前端和后端两个 submodule" -
关联父仓库的远程地址并推送
git remote add origin https://github.com/你的用户名/父仓库.git
git branch -M main
git push -u origin main -
删除之前移出去的两个旧目录
最终结构
父仓库/ ← 父仓库
├── .git/
├── .gitmodules ← 记录两个 submodule 的 URL
├── .git/modules/ ← submodule 的元数据
├── 仓库1/ ← 指向 仓库1 仓库的某个 commit
│ └── .git ← 这是个文件,不是目录,内容 指向 .git/modules
└── 仓库2/ ← 指向 仓库2 仓库的某个 commit
└── .git
OK,到这里我们的目的就算达到了,拥有了一个引用连接到两个子仓库的父仓库,非常完美............吗?
其实不然,目前只是可以引用了,但是子仓库要是更新呢?询问 AI 娘之后的结果是,如果子仓库更新,需要手动去更新父仓库才可以。🤡🤡
何意味?合着我给自己加了个麻烦?不可能,绝对不可能[无图,先欠着🌐]
父仓库代码自动提交
-
父仓库配置接收通知的 Actions
在本地父仓库的根目录下创建
.github/workflows/update-submodule.yml文件name: Update Submodule Reference
on:
# 接收来自子仓库的通知
repository_dispatch:
types: [frontend-updated, backend-updated]
# 也支持手动触发
workflow_dispatch:
jobs:
update-submodule:
runs-on: ubuntu-latest
steps:
- name: Checkout parent repo
uses: actions/checkout@v4
with:
token: ${{ secrets.PARENT_REPO_TOKEN }}
submodules: recursive
fetch-depth: 0
- name: Update submodules to latest
run: |
git submodule update --remote --merge
- name: Commit and push if changed
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add .
if git diff --staged --quiet; then
echo "No changes to commit"
else
git commit -m "chore: 自动更新子模块引用"
git push
fi-
repository_dispatch:监听子仓库发来的自定义事件
-
submodules: recursive:checkout 时拉取所有子模块
-
git submodule update --remote --merge:把子模块更新到最新 commit
-
用 secrets.PARENT_REPO_TOKEN:因为要 push 回父 仓库,需要 Personal Access Token(PAT),而不是默认的 GITHUB_TOKEN(默认 token 无法触发下游 workflow)
-
-
生成 Personal Access Token(PAT)
-
登录 GitHub → 右上角头像 → Settings
-
左侧底部 → Developer settings
-
Personal access tokens → Generate new token (class)
-
勾选权限:
-
✅ repo(完整仓库权限)
-
✅ workflow(如果需要触发其他 workflow)
有效期我选的是永久,省的再续时间了,毕竟是我个人用,没必要搞得太复杂
-
-
生成后立刻复制(只显示一次)
-
回到父仓库 QLink → Settings → Secrets and variables → Actions
-
新建 Secret:名字 PARENT_REPO_TOKEN,值粘贴刚才的 token (这里选地下那个
Repository secrets去创建新的Secret)
-
-
子仓库配置触发通知的 Actions
以仓库1为例,同样在根目录下创建
.github/workflows/update-submodule.yml文件name: Notify Parent Repo
on:
push:
branches:
- main # 改成你子仓库的默认分支(master 或 main)
jobs:
notify:
runs-on: ubuntu-latest
steps:
- name: Trigger parent repo update
uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.PARENT_REPO_TOKEN }}
repository: 用户名/父仓库名
event-type: frontend-updated仓库二只需替换
event-type为父仓库yaml文件中repository_dispatch里对应的名字即可 -
给子仓库也配置 Token
以仓库1为例
进入 qlink-frontend 仓库 → Settings → Secrets and variables → Actions → New repository secret:
-
Name: PARENT_REPO_TOKEN
-
Value: 粘贴刚才生成的那个 PAT
-
以上的部分内容为我直接CV AI 的结果,因为我懒,不要喷写的像 AI🫡,因为它就是 AI 写的😋
OK了,老铁们。本篇文章应该就到此为止了,毕竟我滴任务完成啦💥。其实后面还可以搞搞脚本的优化,像是父仓库能显示具体的子仓库提交了什么代码?如果自动化流程错误的话邮件通知?
如果大家有更好的想法欢迎联系我,我会找 机会去实践的,祝看到这的,没看到这的小伙伴们都天天开心😎
