Git Submodule
Git Submodule 允許在一個 Git 倉庫中嵌入另一個 Git 倉庫,適合管理專案間的共用資源。
前置條件
建立兩個 GitHub Repo:
- 主 repo:
git-main-module - 子 repo:
claude-skill
建立子 repo
$ mkdir claude-skill
$ cd claude-skill
$ git init
Initialized empty Git repository in .../claude-skill/.git/
$ mkdir skill
$ echo "echo 'Hello from claude-skill'" > skill/demo.sh
$ git add .
$ git commit -m "initial commit of claude-skill"
[master (root-commit) b3afa7d] initial commit of claude-skill
1 file changed, 1 insertion(+)
create mode 100644 skill/demo.sh
$ git branch -M main
$ git remote add origin git@github.com:TLexYuW/claude-skill.git
$ git push -u origin main建立主 repo
$ mkdir git-main-module
$ cd git-main-module
$ git init
Initialized empty Git repository in .../git-main-module/.git/
$ echo "hello main module" >> main.txt
$ git add .
$ git commit -m "initial commit of main module"
[main (root-commit) d7d4992] initial commit of main module
$ git branch -M main
$ git remote add origin git@github.com:TLexYuW/git-main-module.git
$ git push -u origin main在主 repo 加入 Submodule
$ git submodule add git@github.com:TLexYuW/claude-skill.git .claude/skill
Cloning into '.claude/skill'...
remote: Enumerating objects: ...
remote: Counting objects: ...
remote: Compressing objects: ...
remote: Total ... (delta ...)
Resolving deltas: ...
$ git status
On branch main
Changes to be committed:
new file: .gitmodules
new file: .claude/skill
$ git add .
$ git commit -m "Add claude-skill as submodule"
[main a0c1450] Add claude-skill as submodule
2 files changed, 4 insertions(+)
create mode 100644 .gitmodules
create mode 160000 .claude/skill
$ git push origin main主 repo 目錄結構
git-main-module/
│ main.txt
│ .gitmodules
└─ .claude/
└─ skill/
└─ demo.sh.gitmodules 檔案內容
[submodule ".claude/skill"]
path = .claude/skill
url = git@github.com:TLexYuW/claude-skill.gitClone 主 repo 含 Submodule
$ git clone git@github.com:TLexYuW/git-main-module.git
$ cd git-main-module
# 初始化 submodule
$ git submodule update --init --recursive
# 或者直接一次完成
$ git clone --recurse-submodules git@github.com:TLexYuW/git-main-module.gitClone 後
.claude/skill 目錄會包含子 repo 完整檔案。更新子 repo
假設在子 repo 新增檔案:
$ cd .claude/skill
$ echo "echo 'New file from submodule'" > new_script.sh
$ git add .
$ git commit -m "Add new script in claude-skill"
$ git push origin main同步主 repo 指向最新子 repo commit
回到主 repo:
$ cd ../.. # 回到 git-main-module
$ git submodule update --remote --merge
Submodule path '.claude/skill': checked out 'abcd1234'
$ git add .claude/skill
$ git commit -m "Update submodule claude-skill to latest"
$ git push origin mainSubmodule 更新需要兩層 commit:
- 子 repo commit
- 主 repo commit 指向新的子 repo commit hash
修改子 repo 後直接在主 repo 推回
# 修改子 repo
$ cd .claude/skill
$ echo "echo 'Update from main module'" >> update_script.sh
$ git add .
$ git commit -m "Update from main module"
$ git push origin main
# 回到主 repo commit pointer
$ cd ../..
$ git add .claude/skill
$ git commit -m "Update submodule pointer after local change"
$ git push origin mainSubmodule 兩層 commit 原則:修改子 repo → push 子 repo → commit pointer in main repo → push main repo
刪除 Submodule
$ git submodule deinit .claude/skill
$ git rm --cached .claude/skill
$ rm -rf .git/modules/.claude/skill
$ git commit -m "Remove submodule claude-skill"
$ rm -rf .claude/skill
$ git push origin mainSubmodule 注意事項
優點
- 精準鎖定子 repo commit
- 適合明確依賴
缺點
- Clone 需要額外步驟
- 更新需要兩層 commit
- CI/CD 操作需要注意 submodule 初始化
操作重點
| 操作 | 指令 |
|---|---|
| 新增子 repo | git submodule add <url> <path> |
| Clone 或更新 | git submodule update --init --recursive |
| 拉最新子 repo | git submodule update --remote --merge |
| 修改後推送 | 修改子 repo → push → 主 repo commit pointer → push |
| 刪除 | deinit + rm --cached + rm -rf .git/modules + commit |