Reposoup: Submodule入りのコミットを普通のtreeに変換する
とりあえず前回必要なプリミティブは用意したので、実際のリポジトリを普通のtreeに変換してみる。
ビルドノードへのソースコード配布のための前処理が目的なので、 この処理自体はbareリポジトリ上で行う 。
prev
.gitmodules
のパース
これはプリミティブか。。 .gitmodules
は .git/config
と同じ形式のファイルであるため、 git config
コマンドでそのままパースできる。
また、 git config
コマンドは、オプション --blob
により実ファイルではなくリポジトリから直接コンフィグファイルを読み取ることもできる。
# URLを取得する場合
$ git config --blob HEAD:.gitmodules --get-regexp "submodule.*.url"
# Submoduleの配置先のパスを取得する場合
$ git config --blob HEAD:.gitmodules --get-regexp "submodule.*.path"
再帰処理に対応していない版
まぁ↑をそのまま実装すれば良い。
ちょっと工夫があるのは fetch
で、--jobs
と --multiple
オプションで並列してfetchを行うようにしている。 --multiple
オプションではrefspecを与えられなくなるが、今回の用途では問題ない。
実際には、手元のリポジトリ(yunibaseやemscripten2native)はどちらもSubmoduleを再帰的に使用している。このため、configの生成をワンショットで行うことはできず、コミットの取得 → .gitmodulesのパース → 個々のpathからコミットを取得 → ... を再帰的に実行しなければならない。
再帰的なremote追加 / fetchの実施
fetchまでは特にポイントはない。基本的には並列に処理できる。実際に submodule を通常のtreeに変換する場合は順序の問題が出てくる。
read-tree --prefix
はbareリポジトリだとダメ
Error: Command failed: git read-tree --prefix=native/imgui/imgui 59da01901ed71a53e5578c34d90d631757c3870d
fatal: this operation must be run in a work tree
適当でも良いので GIT_WORK_TREE
環境変数を設定しておく必要がある。
実際の置き換えを行う
処理は2passで実装している。
- 最初のpass (
step
) は、["submoduleになっているパス", "参照しているコミット"]
のペアのリストを出力する - 実際の置き換えpass (
do_replace
) は、最初のpassが出力したペアを先頭から順番に置き換えていく
置き換えたパスのrootに .gitmodules
ファイルがあった場合は削除しているが、更に、元のリポジトリのrootの .gitmodules
も追加で削除している。 .gitmodules
を消す必要があるかは何とも言えないが、Gitの --recurse-submodule
オプションが .gitmodules
を見ているのか自信が無かったので念のため消しておく事にした。