Open3

Reposoup: コミット情報リポジトリの実装

okuokuokuoku

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

の出力だが、処理の簡単のためいくつか制約を設ける。

  1. 子ブランチのファイルには ブランチポイントを除いて 親ブランチ以前の履歴は含めない
  2. マージコミットの右側の履歴は含めない(全てのマージコミットはsquash mergeとして扱う)
  3. 親ブランチを持たないブランチの終端はSentinelとして空のtree 4b825dc642cb6eb9a060e54bf8d69288fbee4904 を埋める

(EDIT: 出力の加工はやらない方針にした。)

よって、

$ git rev-list --first-parent --right-only refs/heads/master...refs/heads/OneDrive

のように --right-only <親>...<子> を使って子のコミットのみを列挙する。 ... でコミット両者のmerge-base以降のヒストリ、 --right-only はヒストリを木として見たときの右側だけを取得させる。

okuokuokuoku

コミット情報

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 を使わず、以下のアルゴリズムを使って自前で抽出する。

  1. treediff.txt からコミットで導入された oid のリストを得る
  2. git cat-file -s <OID> してサイズを得る
  3. サイズが512bytes以下だったら、 git cat-file -p <OID> して内容を取得し、LFSのポインタファイルかどうかを判別する
  4. <LFS-OID> <SIZE> <PATH> の順に lfs-blobs.txt に書き込む