Open3
Reposoup: コミット情報リポジトリの実装
ちょっと前回( https://zenn.dev/okuoku/scraps/d97e9401c04426 )ので試作してみたけど方針が決まりきらなかったので再度。
branches.txt
: 監視対象ブランチのリスト
$ cat branches.txt
master refs/heads/master
OneDrive refs/heads/OneDrive
全ブランチを追跡すると無駄に容量を喰うので、手動でいくつか監視対象を設定する。派生ブランチはスペース2コで字下げ。
refs.txt
: 全ブランチのリスト
これは git show-ref
の出力を保存すればOK。
$ git show-ref
de7593d9505df5b73f4fc75b1ddeaa611fad0e9e refs/heads/OneDrive
7a68c1448e33ad9d72f2ff752c5c0a72cff84fbc refs/heads/master
commits.txt
: 全コミットのリスト
git rev-list
には --all
オプションがあり、リポジトリに存在するコミットをこれで全て列挙できる。列挙順は基本的には安定している。
$ git rev-list --all > commits.txt
<BRANCH>-history.txt
: ブランチの線形履歴リスト
基本的には、
$ git rev-list refs/heads/master > master-history.txt
の出力だが、処理の簡単のためいくつか制約を設ける。
- 子ブランチのファイルには
ブランチポイントを除いて親ブランチ以前の履歴は含めない - マージコミットの右側の履歴は含めない(全てのマージコミットはsquash mergeとして扱う)
親ブランチを持たないブランチの終端はSentinelとして空のtree4b825dc642cb6eb9a060e54bf8d69288fbee4904
を埋める
(EDIT: 出力の加工はやらない方針にした。)
よって、
$ git rev-list --first-parent --right-only refs/heads/master...refs/heads/OneDrive
のように --right-only <親>...<子>
を使って子のコミットのみを列挙する。 ...
でコミット両者のmerge-base以降のヒストリ、 --right-only
はヒストリを木として見たときの右側だけを取得させる。
コミット情報
1コミット1ディレクトリでコミットの情報を格納していく。
raw.txt
git show --pretty=raw -s HEAD > raw.txt
treediff.txt
git -c "diff.renamelimit=9999999" diff --no-abbrev --raw HEAD^..HEAD > treediff.txt
コミットのfirst-parentとの差分。
linediff.txt
git -c "diff.renamelimit=9999999" diff --numstat HEAD^..HEAD > linediff.txt
テキストファイルの行差分。バイナリファイルの場合は - -
になるので、このファイルを使ってバイナリファイルかどうかを検出することになる。
blobs.txt
linediff.txt
でバイナリファイルと判別したファイルを git cat-file -s <OID>
で得たファイルサイズと共に <OID> <SIZE> <PATH>
の順に記録する。
lfs-blobs.txt
git-lfs
を使わず、以下のアルゴリズムを使って自前で抽出する。
-
treediff.txt
からコミットで導入された oid のリストを得る -
git cat-file -s <OID>
してサイズを得る - サイズが512bytes以下だったら、
git cat-file -p <OID>
して内容を取得し、LFSのポインタファイルかどうかを判別する -
<LFS-OID> <SIZE> <PATH>
の順にlfs-blobs.txt
に書き込む