Open4

yunibuild: Git submoduleを再帰的にミラーしたい

okuokuokuoku

いろいろ考えてみたけど、これ多分簡単な方法は無いよね。。簡単なスクリプトを書くか。。

ターゲット

手元の(公開)プロジェクトでsubmoduleを使ったインテグレーションをしているのは:

やることとしては:

  1. これらの master ブランチのHEADの .gitmodules から再帰的に辿っていって、全部のGitリポジトリのリストを作る/更新する
  2. リストに載っているリポジトリを url.<URL>.insteadOf で書き換えるようなコマンドを出力する -- (全体の置き換えではなく、)単なるリファレンスとしてだけ使うみたいのがあった気もする
  3. 再帰的にshallowなcloneをするスクリプトを書く -- 最近のGitは標準のコマンドでできた気もする
okuokuokuoku

.gitmodules だけfetchする

filter=blob:none でshallow cloneしてから、

git clone --depth=1 --no-checkout --filter=blob:none https://github.com/okuoku/yunibase yunibase

cat-file するのが一番安いと思うんだけどどうかな。。(自動的に当該オブジェクトが取得される)

git cat-file HEAD:.gitmodules

ファイルのハッシュは ls-tree にある oid から求められる。 .gitmodules が変更されていないなら操作する必要は無い。

% git ls-tree HEAD            
100644 blob 6b8710a711f3b689885aa5c26c6c06bde348e82b	.dockerignore
100644 blob 0e6b2e55756cea827d8f50be8e122ccd602568b3	.gitmodules

取得した .gitmodules は git のconfigと同じフォーマットなので、同様に git config コマンドでパースできる。

https://zenn.dev/link/comments/1e7e7fdddacbe1

...というか blob を直接アクセスできるんだから、bare repositoryで良いな。

% git clone --depth=1 --bare --filter=blob:none https://github.com/okuoku/yunibase yunibase
% GIT_DIR=yunibase git ls-tree HEAD .gitmodules        
100644 blob 0e6b2e55756cea827d8f50be8e122ccd602568b3	.gitmodules
% GIT_DIR=yunibase git config --blob HEAD:.gitmodules --get-regexp "submodule.*.url"
okuokuokuoku

llvm-projectの挙動がおかしい

EDIT: たぶんだけどGitHubはPRのマージ先が更新されると merge のrefを自動的に更新してるんではないか説。じゃぁ常時大量のPRが出ているようなプロジェクトをmirrorするのは良くないな。。本質的にmirrorが必要なのは自分のプロジェクトだけだし。。

LLVMは超巨大なGitリポジトリをGitHub上に持っている https://github.com/llvm/llvm-project 。これを --mirror でcloneすると挙動がおかしくなる。

https://zenn.dev/okuoku/scraps/352ad4c421ed1e

とりあえず最初のcloneに失敗するのは http.postBuffer の指定で治ったが、fetchするたびに大量のrefが更新される症状が出る。

From https://github.com/llvm/llvm-project
 - [deleted]                   (none)     -> refs/pull/106948/merge
   e1bde1c5b203..2a9f93bf13c7  main                   -> main
 + f493c7a6795c...33d50dcfec4c refs/pull/100579/merge -> refs/pull/100579/merge  (forced update)
 + ad47ac69d797...2492d99df489 refs/pull/100608/merge -> refs/pull/100608/merge  (forced update)
 + c2a1ea6bd4d7...6a5fb9c33ed1 refs/pull/100667/merge -> refs/pull/100667/merge  (forced update)
 + c469b0a9da8f...bc5c0eb9f6d8 refs/pull/100785/merge -> refs/pull/100785/merge  (forced update)
 + 3315eaec0aa4...b4eb5d5369f2 refs/pull/100977/merge -> refs/pull/100977/merge  (forced update)
 + 40760ecdb24b...c1e307603e28 refs/pull/100995/merge -> refs/pull/100995/merge  (forced update)
 + 129ccc3cf7b2...ff32630fb23b refs/pull/101053/merge -> refs/pull/101053/merge  (forced update)
 + f895b92ba805...39544d3888f4 refs/pull/101172/merge -> refs/pull/101172/merge  (forced update)
 + a9305b1263fe...fd5f12253cd7 refs/pull/101261/merge -> refs/pull/101261/merge  (forced update)
 + 607124ea1b4d...0593d2b11420 refs/pull/101485/merge -> refs/pull/101485/merge  (forced update)

106948は実際このタイミングでマージされたPR https://github.com/llvm/llvm-project/pull/106948 なので良いとして、他のPRを参照しているrefは特にGHEのページを見ても更新されている様子がない。

本質的にmirrorが必要なのは自分がPRを出すリポジトリだけだから、こういう例外的なリポジトリは --mirror ではなく --bare でcloneできるようにdenylistの仕組みを作るのが良いかな。。