Git Submodule

Git Submodule を使用(しよう) すると、Git リポジトリ(ない)(べつ) の Git リポジトリを()() むことができます。プロジェクト(かん)共有(きょうゆう) リソース管理(かんり)(てき) しています。

前提条件

2つの GitHub Repo を作成(さくせい)

  • メイン repogit-main-module
  • サブ repoclaude-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.git

Submodule を含むメイン repo を Clone

$ 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.git
Clone ().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 main

Submodule の更新(こうしん) には2(そう) の commit が必要(ひつよう)

  1. サブ repo の commit
  2. メイン 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 main
Submodule 2(そう) commit 原則(げんそく) :サブ repo を修正(しゅうせい) → サブ repo を push → メイン repo の commit pointer → メイン repo を push

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 main

Submodule の注意事項

メリット

  • サブ repo の commit を正確(せいかく) にロック
  • 明確(めいかく)依存(いぞん) 関係(かんけい)(てき) している

デメリット

  • Clone に追加(ついか) のステップが必要(ひつよう)
  • 更新(こうしん) に2(そう) の 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