Lazy Diary @ Hatena Blog

PowerShell / Java / miscellaneous things about software development, Tips & Gochas. CC BY-SA 4.0/Apache License 2.0

submoduleとsubtreeの.gitディレクトリの違い

submoduleの場合

  • コミットが1つもないリポジトリにはsubmoduleの追加はできない
  • submoduleの先のオブジェクトは.gitディレクトリには保存されない
$ git clone https://github.com/satob/main-submodule.git
Cloning into 'main-submodule'...
warning: You appear to have cloned an empty repository.

$ cd main-submodule/

$ git commit --allow-empty -n -m "Initial commit."
[master (root-commit) c2270a0] Initial commit.

$ git submodule add https://github.com/satob/subproject.git
Cloning into 'C:/home/satob/git/main-submodule/subproject'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.

$ find .
.
./.git
./.git/COMMIT_EDITMSG
./.git/config
./.git/description
./.git/HEAD
./.git/hooks
./.git/hooks/applypatch-msg.sample
./.git/hooks/commit-msg.sample
./.git/hooks/fsmonitor-watchman.sample
./.git/hooks/post-update.sample
./.git/hooks/pre-applypatch.sample
./.git/hooks/pre-commit.sample
./.git/hooks/pre-push.sample
./.git/hooks/pre-rebase.sample
./.git/hooks/pre-receive.sample
./.git/hooks/prepare-commit-msg.sample
./.git/hooks/update.sample
./.git/index
./.git/info
./.git/info/exclude
./.git/logs
./.git/logs/HEAD
./.git/logs/refs
./.git/logs/refs/heads
./.git/logs/refs/heads/master
./.git/modules
./.git/modules/subproject
./.git/modules/subproject/config
./.git/modules/subproject/description
./.git/modules/subproject/HEAD
./.git/modules/subproject/hooks
./.git/modules/subproject/hooks/applypatch-msg.sample
./.git/modules/subproject/hooks/commit-msg.sample
./.git/modules/subproject/hooks/fsmonitor-watchman.sample
./.git/modules/subproject/hooks/post-update.sample
./.git/modules/subproject/hooks/pre-applypatch.sample
./.git/modules/subproject/hooks/pre-commit.sample
./.git/modules/subproject/hooks/pre-push.sample
./.git/modules/subproject/hooks/pre-rebase.sample
./.git/modules/subproject/hooks/pre-receive.sample
./.git/modules/subproject/hooks/prepare-commit-msg.sample
./.git/modules/subproject/hooks/update.sample
./.git/modules/subproject/index
./.git/modules/subproject/info
./.git/modules/subproject/info/exclude
./.git/modules/subproject/logs
./.git/modules/subproject/logs/HEAD
./.git/modules/subproject/logs/refs
./.git/modules/subproject/logs/refs/heads
./.git/modules/subproject/logs/refs/heads/main
./.git/modules/subproject/logs/refs/remotes
./.git/modules/subproject/logs/refs/remotes/origin
./.git/modules/subproject/logs/refs/remotes/origin/HEAD
./.git/modules/subproject/objects
./.git/modules/subproject/objects/58
./.git/modules/subproject/objects/58/5ed533145468fd0cbd3d037ada853dee3fd61c
./.git/modules/subproject/objects/84
./.git/modules/subproject/objects/84/f151a3c527fea0d345a6fe18701d9ad7a8ff01
./.git/modules/subproject/objects/b8
./.git/modules/subproject/objects/b8/3915ccc4b8e766ca866c6bd9b7b95a215811e4
./.git/modules/subproject/objects/info
./.git/modules/subproject/objects/pack
./.git/modules/subproject/packed-refs
./.git/modules/subproject/refs
./.git/modules/subproject/refs/heads
./.git/modules/subproject/refs/heads/main
./.git/modules/subproject/refs/remotes
./.git/modules/subproject/refs/remotes/origin
./.git/modules/subproject/refs/remotes/origin/HEAD
./.git/modules/subproject/refs/tags
./.git/objects
./.git/objects/4b
./.git/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904
./.git/objects/ac
./.git/objects/ac/7077f2309b6eb842526824ab440710afb775d8
./.git/objects/c2
./.git/objects/c2/270a0374afb874ea020800e22b8b50ccfab4a9
./.git/objects/info
./.git/objects/pack
./.git/refs
./.git/refs/heads
./.git/refs/heads/master
./.git/refs/tags
./.gitmodules
./subproject
./subproject/.git
./subproject/README.md

$ for i in `find .git/objects -type f`; do hash=`echo $i | cut -f 3-4 -d "/" | tr --delete "/"`; echo ==== $hash ====; git cat-file -p $hash; done
==== 4b825dc642cb6eb9a060e54bf8d69288fbee4904 ====
==== ac7077f2309b6eb842526824ab440710afb775d8 ====
[submodule "subproject"]
        path = subproject
        url = https://github.com/satob/subproject.git
==== c2270a0374afb874ea020800e22b8b50ccfab4a9 ====
tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904
author SATO Yusuke <yusuke.sato.zz@gmail.com> 1695224761 +0900
committer SATO Yusuke <yusuke.sato.zz@gmail.com> 1695224761 +0900

Initial commit.

subtreeの場合

  • コミットが1つもないリポジトリでもsubtreeは追加できる
  • subtreeコマンドの実行前に追加対象のリポジトリをremoteに追加する必要がある
  • subtreeの先のオブジェクトも.gitディレクトリに保存される
$ git clone https://github.com/satob/main-subtree.git
Cloning into 'main-subtree'...
warning: You appear to have cloned an empty repository.

$ cd main-subtree/

$ git remote add subproject https://github.com/satob/subproject.git

$ git subtree add --prefix=subproject --squash subproject main
git fetch subproject main
warning: no common commits
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.
From https://github.com/satob/subproject
 * branch            main       -> FETCH_HEAD
 * [new branch]      main       -> subproject/main
Added dir 'subproject'

$ find .
.
./.git
./.git/COMMIT_EDITMSG
./.git/config
./.git/description
./.git/FETCH_HEAD
./.git/HEAD
./.git/hooks
./.git/hooks/applypatch-msg.sample
./.git/hooks/commit-msg.sample
./.git/hooks/fsmonitor-watchman.sample
./.git/hooks/post-update.sample
./.git/hooks/pre-applypatch.sample
./.git/hooks/pre-commit.sample
./.git/hooks/pre-push.sample
./.git/hooks/pre-rebase.sample
./.git/hooks/pre-receive.sample
./.git/hooks/prepare-commit-msg.sample
./.git/hooks/update.sample
./.git/index
./.git/info
./.git/info/exclude
./.git/logs
./.git/logs/HEAD
./.git/logs/refs
./.git/logs/refs/heads
./.git/logs/refs/heads/master
./.git/logs/refs/remotes
./.git/logs/refs/remotes/subproject
./.git/logs/refs/remotes/subproject/main
./.git/objects
./.git/objects/4b
./.git/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904
./.git/objects/58
./.git/objects/58/5ed533145468fd0cbd3d037ada853dee3fd61c
./.git/objects/77
./.git/objects/77/1a0b22b2c87b8636543405c561585a03d1b2c1
./.git/objects/84
./.git/objects/84/f151a3c527fea0d345a6fe18701d9ad7a8ff01
./.git/objects/85
./.git/objects/85/726968c65ea39963bd7af83bf488b710a02811
./.git/objects/95
./.git/objects/95/818f61bafefcd57d216eb72c67637e1db244a5
./.git/objects/b8
./.git/objects/b8/3915ccc4b8e766ca866c6bd9b7b95a215811e4
./.git/objects/ca
./.git/objects/ca/fcde3608c2e000403302b53486a22f3c285225
./.git/objects/info
./.git/objects/pack
./.git/ORIG_HEAD
./.git/refs
./.git/refs/heads
./.git/refs/heads/master
./.git/refs/remotes
./.git/refs/remotes/subproject
./.git/refs/remotes/subproject/main
./.git/refs/tags
./subproject
./subproject/README.md

$ for i in `find .git/objects -type f`; do hash=`echo $i | cut -f 3-4 -d "/" | tr --delete "/"`; echo ==== $hash ====; git cat-file -p $hash; done
==== 4b825dc642cb6eb9a060e54bf8d69288fbee4904 ====
==== 585ed533145468fd0cbd3d037ada853dee3fd61c ====
tree b83915ccc4b8e766ca866c6bd9b7b95a215811e4
author SATO Yusuke <yusuke.sato.zz@gmail.com> 1695221915 +0900
committer GitHub <noreply@github.com> 1695221915 +0900
gpgsig -----BEGIN PGP SIGNATURE-----

 wsBcBAABCAAQBQJlCwibCRBK7hj4Ov3rIwAAx8AIAKsD9LGVHzpM+tKYoZ45WUOW
 nl8KOEpp1RMCMrfSReV7zUCwoTAbe5edT7YIBla/sYgGK67B6aZXZ1HkdQOd2W4K
 +RiTIX8cYfvu4DRU/cAp2UCsf5GMSjaMjVDNiCLR21TJLzfdVlDjy3plEr4s3o4M
 tsBm9ospopJdTLJguFAs8WSnP+Uju2FV5kS957e2LwGyY26MybEyfPQvHg5EP6rO
 F+tb0weBOX3oCWUMYXMVJI+fQica5epxTN+la1/0yNglycDXV6FzYvP3gZZb7bwa
 IxmvznmBy5BI8NGSpj/M4Gck82BqMrddtu2pydla0T8sQm21EwKInIDuyLvzyFI=
 =wZs0
 -----END PGP SIGNATURE-----


Initial commit==== 771a0b22b2c87b8636543405c561585a03d1b2c1 ====
tree 85726968c65ea39963bd7af83bf488b710a02811
parent cafcde3608c2e000403302b53486a22f3c285225
parent 95818f61bafefcd57d216eb72c67637e1db244a5
author SATO Yusuke <yusuke.sato.zz@gmail.com> 1695224782 +0900
committer SATO Yusuke <yusuke.sato.zz@gmail.com> 1695224782 +0900

Merge commit '95818f61bafefcd57d216eb72c67637e1db244a5' as 'subproject'
==== 84f151a3c527fea0d345a6fe18701d9ad7a8ff01 ====
# subproject
Sub-project for submodule/subtree
==== 85726968c65ea39963bd7af83bf488b710a02811 ====
040000 tree b83915ccc4b8e766ca866c6bd9b7b95a215811e4    subproject
==== 95818f61bafefcd57d216eb72c67637e1db244a5 ====
tree b83915ccc4b8e766ca866c6bd9b7b95a215811e4
author SATO Yusuke <yusuke.sato.zz@gmail.com> 1695224782 +0900
committer SATO Yusuke <yusuke.sato.zz@gmail.com> 1695224782 +0900

Squashed 'subproject/' content from commit 585ed53

git-subtree-dir: subproject
git-subtree-split: 585ed533145468fd0cbd3d037ada853dee3fd61c
==== b83915ccc4b8e766ca866c6bd9b7b95a215811e4 ====
100644 blob 84f151a3c527fea0d345a6fe18701d9ad7a8ff01    README.md
==== cafcde3608c2e000403302b53486a22f3c285225 ====
tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904
author SATO Yusuke <yusuke.sato.zz@gmail.com> 1695224757 +0900
committer SATO Yusuke <yusuke.sato.zz@gmail.com> 1695224757 +0900

Initial commit.