🔄

Git submoduleが空のときの解決方法と基本的な使い方

に公開

問題

サブモジュールディレクトリを設定しているリポジトリをcloneしたときに、サブモジュールディレクトリが空になっていた。

結論

git clone した後、サブモジュールも表示させたい場合は、以下のようにコマンドを実行する。

# サブモジュールを初期化して取得
git submodule update --init

Git submoduleとは

Git submoduleとは、Gitリポジトリ内に別のGitリポジトリを含めるための仕組みです。

  • 親リポジトリにサブモジュールを含めることができる
  • 幅数のプロジェクトで共通のコードを管理する
  • などの用途で使われる。

今回は、obsidianのノートにzennなど、別のリポジトリを組み込むために使用。

今回対応した方法

1. 現在の状況を確認

$ git submodule status
-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa repository-name1
-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb repository-name2
  • 先頭の記号

    • - : サブモジュールが初期化されていない(git submodule update --init がまだ)
    • : 親リポジトリが参照しているコミットと一致
    • + : サブモジュール内で変更がある(親が参照するコミットとズレている)
    • U : サブモジュールにマージ競合がある
  • コミットハッシュ

    • 例: aaaaaaaa...
    • サブモジュールが固定されている特定のコミット

→ ディレクトリは存在するが、サブモジュールが初期化されていない。

2.サブモジュールを初期化

$ git submodule update --init
Submodule 'repository-name1' (https://github.com/username/repository-name1.git) registered for path 'repository-name1'
Submodule 'repository-name2' (https://github.com/username/repository-name2.git) registered for path 'repository-name2'
Cloning into '/Users/soto/p/my-obsidian-notes/repository-name1'...
Cloning into '/Users/soto/p/my-obsidian-notes/repository-name2'...
Submodule path 'repository-name1': checked out 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
Submodule path 'repository-name2': checked out 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'

→ サブモジュールが初期化され、内容が取得された。

3. 結果を確認

$ git submodule status
 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa repository-name1 (heads/main)
 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb repository-name2 (heads/main)

先頭の - が消えて、スペースになっていることが確認できる。

git submodule initgit submodule update --init の違い

1. git submodule init : サブモジュールを初期化する(ファイルは取得しない)

ファイルを取得するためには、git submodule update --init を実行する必要がある。

実行例

サブモジュールを初期化する:

$ git submodule init // サブモジュールを初期化する
Submodule 'repository-name1' (https://github.com/username/repository-name1.git) registered for path 'repository-name1'
Submodule 'repository-name2' (https://github.com/username/repository-name2.git) registered for path 'repository-name2'
  • 役割:

    • .gitmodules に書かれた サブモジュールの設定をローカルに登録 するだけ
    • 実ファイルはまだ取得しない
  • 実行後の状態:

    • .git/config にサブモジュールの URL などが追記される
    • サブモジュールディレクトリは空のまま
  • 用途:

    • 「サブモジュールの登録だけして、まだダウンロードはしたくない」場合

サブモジュールのファイルを取得したい場合は、以下のコマンドを実行する:

$ git submodule update --init
Cloning into '/Users/soto/p/my-obsidian-notes/repository-name1'...
Cloning into '/Users/soto/p/my-obsidian-notes/repository-name2'...
Submodule path 'repository-name1': checked out 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
Submodule path 'repository-name2': checked out 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'

2. git submodule update --init : サブモジュールを初期化&ファイルを取得

初期化したあと、ファイルを取得する。

$ git submodule update --init
  • 役割:

    • init の処理を含みつつ、さらにファイルを取得
    • 親リポジトリが参照する 特定のコミット でサブモジュールをチェックアウト
  • 実行後の状態:

    • サブモジュールの実体がディレクトリ内に展開される
  • 用途:

    • クローン直後に サブモジュールの中身も含めて使いたい場合
    • 一般的にはこちらを使うことが多い

そもそも最初からサブモジュールも含めてcloneしたい

方法1: 順次実行

git clone --recurse-submodules git@github.com:username/main-repo.git
  • 調べていると--recursiveというオプションも出てくるが、これは古くからあるコマンドとのことで、現在は--recurse-submodulesを使用が推奨されるとのこと。
  • 機能的には全く同じ。

方法2: 並列実行

git clone --recurse-submodules -j8 git@github.com:username/main-repo.git
  • -j8コマンドをつけると、サブモジュールのクローンが並列で実行され、時間を短縮できる。
  • ただし、並列実行すると、メモリ使用量が増加する可能性がある。

おわりに

そもそも、obsidianのディレクトリにzennの記事などのファイルもまとめたいと思ったのが、サブモジュールというもの自体を知ることになったきっかけ。
存在すら知らなかったので、まだまだわからないことだらけである。引き続き学んでいきたい。

Discussion