[Git] git submodule は癖がすごいとの噂だったが素直につきあっていけそうという話

memo.

以前にちょっと調べたときに git submodule は癖がすごいようだったので後回しにしていました。

% git --version
git version 1.9.2

プロジェクトにサブモジュールを加える

サブモジュールを追加する

ディレクトリを指定して submodule を追加する。

% git submodule add https://gist.github.com/6694891.git WordPress

関連ファイルが作成される。

% git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)
    new file:   .gitmodules
    new file:   WordPress
.gitmodules
[submodule "WordPress"]
    path = WordPress
    url = https://gist.github.com/6694891.git

.git/config にも記載されているので、git submodule init で初期化する必要は無くなったよう。

.git/config
[submodule "WordPress"]
    url = https://gist.github.com/6694891.git

既にファイルがステージされているので git commit する。

% git commit -m 'add submodule: WordPress'

GitHub へ push したところ、こんな表示がされました。

2014-05-21_git_01

登録したサブモジュールを更新する

登録したサブモジュールを更新します。

% git submodule update
Submodule path 'WordPress': checked out '542a00a3c0be3c6dd40c989f67dfd28dc8772900'

サブモジュール内のサブモジュールも更新したいといった場合、--recursive で再帰的に更新するそう。

% git submodule update --recursive

サブモジュールを削除する

% git submodule deinit WordPress
Cleared directory 'WordPress'
Submodule 'WordPress' (https://gist.github.com/6694891.git) unregistered for path 'WordPress'
% git rm -rf WordPress
rm 'WordPress'

.gitmodules, .git/config からも消えている。
git submodule status にも何も表示されない。

% git submodule status
% git status
On branch master
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)
    modified:   .gitmodules
    deleted:    WordPress
% git commit -m 'delete submodule: WordPress'

サブモジュールを含んだプロジェクトを git clone する

GitHub に追加したサブモジュールを含むプロジェクトを git clone してみます。

2014-05-21_git_01

git clone

% git clone git@github.com:DriftwoodJP/VMs.git submodule_test

サブモジュールのディレクトリには何も含まれていません。

% ls WordPress
% git submodule status
-7e0a09da27c3e6ce563ee5bc7e2b360e0b765101 WordPress

.git/config には情報がないので init します。

% git submodule init
Submodule 'WordPress' (https://gist.github.com/6694891.git) registered for path 'WordPress'

update するとサブモジュール内のファイルをクローンしてくれます。

% git submodule update
Cloning into 'WordPress'...
remote: Counting objects: 18, done.
remote: Compressing objects: 100% (17/17), done.
remote: Total 18 (delta 4), reused 0 (delta 0)
Unpacking objects: 100% (18/18), done.
Checking connectivity... done.
Submodule path 'WordPress': checked out '7e0a09da27c3e6ce563ee5bc7e2b360e0b765101'
% ls WordPress
Vagrantfile   provision.sh

以後、サブモジュールに更新があり、これを反映させたい場合は git submodule update を実行すればよいようです。

git clone –recursive

git clone 時に、submodule init, update も一度に済ませたい場合は、--recursive オプションが使えます。

% git clone --recursive git@github.com:DriftwoodJP/VMs.git submodule_test
Cloning into 'submodule_test'...
remote: Reusing existing pack: 19, done.
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 22 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (22/22), done.
Resolving deltas: 100% (2/2), done.
Checking connectivity... done.
Submodule 'WordPress' (https://gist.github.com/6694891.git) registered for path 'WordPress'
Cloning into 'WordPress'...
remote: Counting objects: 18, done.
remote: Compressing objects: 100% (17/17), done.
remote: Total 18 (delta 4), reused 0 (delta 0)
Unpacking objects: 100% (18/18), done.
Checking connectivity... done.
Submodule path 'WordPress': checked out '7e0a09da27c3e6ce563ee5bc7e2b360e0b765101'

サブモジュールの中を更新したい場合はブランチをきる

のちのち、git submodule update で作業が消えないようにブランチを切ります。

% git checkout -b 'work'
Switched to a new branch 'work'

サブモジュール内で、今回のプロジェクトに合うようにファイルを変更しました。

% git add .
% git commit -m 'Update submodule: Ready for this project'
[work cecf526] Update submodule: Ready for this project
 2 files changed, 3 insertions(+), 2 deletions(-)
 create mode 100644 .gitignore

サブモジュールの外に出て、ステータスを確認します。
新しいコミットがあるよと教えてくれます。

% cd ../
% git status
On branch dev
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)
    modified:   WordPress (new commits)
no changes added to commit (use "git add" and/or "git commit -a")

外側でも、git add して git commit します。

% git add WordPress
% git commit -m 'Update VagrantFile: Ready for this project'
[dev c9f1f5b] Update VagrantFile: Ready for this project
 1 file changed, 1 insertion(+), 1 deletion(-)

つよがってみましたが、先人のおかげで何とかなりそうです。

補遺

以前と同じ名前でサブモジュールを追加するとこんなことを言われるので、指示通り -f を付けるか別の名前を付けるかすればよい。

% git submodule add https://gist.github.com/6694891.git WordPress
A git directory for 'WordPress' is found locally with remote(s):
  origin    https://gist.github.com/6694891.git
If you want to reuse this local git directory instead of cloning again from
  https://gist.github.com/6694891.git
use the '--force' option. If the local git directory is not the correct repo
or you are unsure what this means choose another name with the '--name' option.
% git submodule add -f https://gist.github.com/6694891.git WordPress
Reactivating local git directory for submodule 'WordPress'.

transitive.info – Git 使い方 見出し一覧 がすごい。