Reposoup: Bareリポジトリ上でSubmoduleを直接操作する
手元のプロジェクトではyunibase https://github.com/okuoku/yunibase や WasmLinux https://github.com/okuoku/wasmlinux-project のようにインテグレーションにsubmoduleを使っているものが多い。
これらを分析に廻すときにbareリポジトリ上で各種操作を直接行えると嬉しい。つまり、
- Submodule参照/更新をrefに変換する
- Submoduleが指しているrefを更新する
- Submoduleが指しているrefをtreeに変換する
参照をrefにする
これは単に ls-tree
で良い。つまり、例えば yunibase https://github.com/okuoku/yunibase において、
$ git ls-tree --no-abbrev HEAD yuni
160000 commit 1c35e56c528b9d2152cd40315b448acdad7b838d yuni
として得られる commit
はrefになっている。
ただし、この ref を直接元リポジトリ上で使うことはできない。
$ git show 1c35e56c528b9d2152cd40315b448acdad7b838d
fatal: bad object 1c35e56c528b9d2152cd40315b448acdad7b838d
... remoteに足してしまうのが一番簡単だと思う。
$ git remote add yuni git@github.com:okuoku/yuni
$ git fetch yuni
$ git show --pretty=oneline 1c35e56c528b9d2152cd40315b448acdad7b838d
1c35e56c528b9d2152cd40315b448acdad7b838d (yuni/master) r7c: Fix `unquote`
実際には .git/modules
以下にGitリポジトリができているので、そちらを GIT_DIR
に指定すればアクセスはできる。(が、今回はrefをtreeに変換したいのでこの方法は使えない。)
更新をrefにする
diff
でできる。
$ git diff --no-abbrev --raw HEAD HEAD^
:160000 160000 6b556d3a7a609cced3c48779a2028656fff132f5 37b39693edac94964070814255794a0d802c9829 M impl-current/cyclone
:160000 160000 d31d82960231a4fde04b4765ea911ff4b5dacf79 e0109790d0128e93808d7a9472cd531778ab00c8 M impl-stable
Submodule 用には専用の mode 160000
がアサインされているので、これを確認すれば良い。
refを更新する
今回はsubmodule yuni/
を1つ前のコミットに戻してみる f3e41162fc8f25571c11bea34bdfe5d28b56c44a
。
$ git read-tree HEAD
$ git update-index --cacheinfo 160000,f3e41162fc8f25571c11bea34bdfe5d28b56c44a,yuni
$ git commit -m TEST
[master 5b306f0] TEST
1 file changed, 1 insertion(+), 1 deletion(-)
$ git show
commit 5b306f09a9b711362fad9ff56f8ed7e3ad3d5563 (HEAD -> master)
Author: okuoku <mjt@cltn.org>
Date: Sat May 4 14:08:55 2024 +0900
TEST
diff --git a/yuni b/yuni
index 1c35e56..f3e4116 160000
--- a/yuni
+++ b/yuni
@@ -1 +1 @@
-Subproject commit 1c35e56c528b9d2152cd40315b448acdad7b838d
+Subproject commit f3e41162fc8f25571c11bea34bdfe5d28b56c44a
普通に update-index
の cache-info
に mode 160000
としてオブジェクトを渡せば良い。
Submoduleを普通のディレクトリに変換する
(逆方向、つまり普通のディレクトリをSubmoduleに変換するのは↑のように単に 160000
で直接突っ込めば良い)
この処理は read-tree
コマンドで行えるが、 事前にsubmoduleだったリポジトリをfetchしている必要がある 。
$ git remote add yuni git@github.com:okuoku/yuni
$ git fetch yuni
いわゆるsubtree mergeを行うときと同様に、 --prefix=
で元々のSubtreeの場所にコミットを読み込むことができる。(read-treeは treeish を取るためcommitを直接指定して良い)
$ git read-tree --prefix=yuni 1c35e56c528b9d2152cd40315b448acdad7b838d
$ git commit -m TEST
[master 9d8f9a5] TEST
737 files changed, 51875 insertions(+), 1 deletion(-)
delete mode 160000 yuni
create mode 100644 yuni/.gitignore
create mode 100644 yuni/CMakeLists.txt
:
履歴は一切受けつがれない。履歴を保持したい場合はSubtree mergeとするしかない。