Reposoup: リポジトリのフラット化、フレーク化
営業上の都合でちゃんと内部ツールに用語を振って整理することにしたので、理解が激烈に難しい写像リポジトリ2種をどう説明するか真面目に考えたい。。
(以下、 " " で囲む用語は造語)
"写像リポジトリ"
※ そもそも厳密には数学的な意味での写像でない ので何か改名しないといけない。後から概念を拡張したので。。
"写像リポジトリ"とは、ある時系列リポジトリを処理して別の時系列リポジトリに変換したものを指す。例えば、npmとかNugetのようなバージョン管理機能付きのパッケージシステムは、ソースコードリポジトリをビルドに変換した写像リポジトリと言える。
パッケージ管理システムがソースコードリポジトリの写像リポジトリになるのは、あるプロジェクトのビルドが Reproducible であるときに自明になる(あるバイナリパッケージには一意に対応するソースコードリビジョンが存在する)。
現実的にはビルドはreproducibleでないことが多いので、リポジトリのリビジョン同士の関係を手動で管理することで無理矢理写像リポジトリと見做すようにする。
... 言い替えると、ソフトウェアのビルドを関数と見做したとき、パッケージシステムはソースコードリポジトリの写像リポジトリとなる。
で、他の写像を考えると便利なんじゃないかということで考え出したのが、"フラット化"リポジトリ と "フレーク化"リポジトリという事になる。これらのリポジトリは、リポジトリの分析に必要な情報を格納している。
Git scraping
Gitリポジトリをデータベースとして活用するものには先例がある。
写像リポジトリのアイデアは、このGit scraping / Flat Dataのアイデアをソフトウェア分析の分野に持ってくるにあたって必要なものになる。
フラット化リポジトリ
"フラット化リポジトリ" は、リポジトリメタデータのリポジトリと言える。つまり、Gitで言うところの
- tree
- commit
の各オブジェクトをファイルに落としてGitリポジトリにしたものと言える。ただし、フラット化リポジトリはこれらだけではなく、より重要なデータ:
- ファイル名履歴
も生成して保持する。
リポジトリの形式
リポジトリは .git/objects
のような感じでファイルを記録する。
用途
例えば、通常GitHubではコミットの列挙にはAPIの呼出しが必要で、これはrate limitがある。しかし、GitHubを利用したCDNを通してフラット化リポジトリをアクセスすることでコミットのデータを無料でクエリできる。
ファイル名の履歴
ファイル名の履歴は殆どのVCSでは直接的には管理されていないため、履歴を解析して生成してやる必要がある。
Gitはそもそもファイル名の履歴を一切管理していない。このため、rename等の操作をGitリポジトリに記録することがそもそもできない。Subversionはrename操作をリポジトリに記録することができる。このようにVCSによって、履歴のconfidenceには差があるが、現状はGitのようなヒューリスティックによって生成されるrenameもrenameとして受け入れる方針にしている。(つまり、フラット化リポジトリはリポジトリの履歴から一意には生成されない可能性がある)
ファイル名の履歴を記録するには、"ファイルID"を振る必要がある。このIDは SHA256(ファイルが初出現したコミットハッシュ + フルパス名)
で生成する。 +
は文字列的な連結。
Subversionのようにブランチ作成をディレクトリのcopyで表現するVCS(頭おかしいんじゃねぇの)ではブランチの作成毎にリネームを実施する のではなく 、ブランチの作成後にファイルが変更された際 = 実際のdiffが発生した際にリネームを実施したものとして見做す。(この性質により、フラット化リポジトリは元のリポジトリを再現できない。)
... これ別のリポジトリにした方が良かったりする。。?別のリポジトリに分割した方が良いね...
- Gitメタデータ
- Gitアノテーション (graft等)
- Subversionアノテーション(コミットメッセージやmergeinfo等の属性)
Subversionはコミットメッセージやmergeinfoがimmutableではない(頭おかしいんじゃねぇの)。Gitにおけるcommitやtreeはimmutableなオブジェクトとなるため、アノテーションと混ぜなければ一意なリポジトリを作成することが原理的には可能となる。
フレーク化リポジトリ
"フレーク化" とは、ファイルを行単位に分割することを指す。フレーク化されたソースコードの1行1行について、 SHA256(初出現のファイルID + リビジョン番号 + 行番号)
による "フレークID" を振り、個別のオブジェクトとして格納する。ここで使うファイルIDのためにフラット化リポジトリを作成する必要がある。
また、個々のフレーク化された行の集合として各ファイルを表現し、そのリストも格納する。
これにより、 blame
の結果をリポジトリ上で管理することができるようになる。
用途
コンパイラ警告など、 リビジョン x パス名 x 行番号 で表現できるデータをフレークIDに置き換えることで、ファイルが編集されても一意さを保つ警告に変換することができる。