できない.dev

Git submodule のファイルが空のまま更新できない

submodule は clone 時に自動取得されない。
--recurse-submodules 付きで clone するか、後から git submodule update --init --recursive を実行する。
親リポジトリと submodule は別の HEAD を持つため pull とのセット運用も必要。

公開: 更新:

要約

Git submodule のディレクトリは clone しただけでは中身が空のまま。git clone --recurse-submodules を付けるか、後から git submodule update --init --recursive を実行することで取得できる。
親リポジトリと submodule は別の HEAD を持つので、親を pull した後の同期も忘れやすい。

よくある原因

  1. clone 時にオプション未指定: git clone <url> だけ実行すると .gitmodules に書かれた submodule の中身は取得されず、ディレクトリだけが空の状態で作られる。
  2. submodule 初期化忘れ: 後から submodule が追加されたリポジトリで git pull しても、submodule ディレクトリは空のままで git submodule update --init が必要。
  3. 親リポジトリの更新後: 親が submodule の新しいコミットを指していても、ローカルの submodule HEAD は古いコミットのままになり、git submodule update で追従させる必要がある。
  4. URL 変更未反映: .gitmodules で submodule の URL が変わったが、ローカルの .git/config 側は古い URL を保持しているため fetch 先が間違っている。

解決策

1. 初回 clone でまとめて取得

git clone --recurse-submodules https://example.com/parent.git

--recurse-submodules を付けると、親 clone 完了後に自動で submodule init + submodule update が走る。

2. 既存 clone を初期化する

git submodule update --init --recursive

--init.gitmodules を読み .git/config に submodule を登録するステップ、--recursive はネストした submodule にも適用する。
詳しくは git-submodule 公式ドキュメント(新しいタブで開く) を参照。

3. 親の pull とセットで実行

git pull
git submodule update --init --recursive

親の commit が submodule の新しい SHA を指していると、git statusmodified content と表示されることがある。update で submodule の HEAD を親が指す SHA に揃える。

4. URL が変わったとき

git submodule sync --recursive
git submodule update --init --recursive

.gitmodulesurl 行を .git/config 側に反映するのが sync
リポジトリ移行後にはこの 2 行を流すと安全。
さらに踏み込んだ運用は Pro Git の Submodules 章(新しいタブで開く) が詳しい。

実行例

実際に alpine/git(Git 2.54.0)環境で上記の手順を走らせると、--recurse-submodules を付けずに clone した直後は vendor/sub が空のままとなり、git submodule update --init --recursive を実行した時点で vendor/sub への登録・clone・チェックアウトが完了し、終了コード 0 で lib.txt が取得できることを確認している。

$ git clone parent parent-clone
Cloning into 'parent-clone'...
done.
$ ls -A parent-clone/vendor/sub
$ git submodule update --init --recursive
Submodule 'vendor/sub' (/tmp/tmp.fECKOJ/sub) registered for path 'vendor/sub'
Cloning into '/tmp/tmp.fECKOJ/parent-clone/vendor/sub'...
done.
Submodule path 'vendor/sub': checked out '382c7f242cf2e25e9d5c6b83a6002b79f9869a17'
終了コード: 0
$ ls -A vendor/sub
.git
lib.txt
$ cat vendor/sub/lib.txt
hello from submodule

— 2026-08-02 時点の出力

この記事は役立ちましたか?