7月17日、Drew Silcock氏が「Artisanal Handcrafted Git Repositories」と題したブログ記事を公開した。この記事では、Gitレポジトリを“手作業”で構築しながら、その内部構造を学ぶ方法について詳しく紹介されている。以下に、その内容を紹介する。
手作業で始めるGitレポジトリ
.git
ディレクトリを自分の手で作る
Git porcelain(高水準コマンド)を封印し、以下のように必要なサブディレクトリを自前で用意するところから物語は始まる。
# ブランチやオブジェクトを格納するための最低限の構造
$ mkdir -p .git/hooks .git/info .git/objects/info .git/objects/pack \
.git/refs/heads .git/refs/remotes .git/refs/tags .git/logs
# リポジトリ専用設定ファイル(例)
$ cat <<EOF > .git/config
repositoryformatversion = 0
EOF
最後に HEAD
を用意し、デフォルトブランチ main
を指すように設定する。
$ echo "ref: refs/heads/main" > .git/HEAD
git status
を実行すれば、Gitが “手作業リポジトリ” を正しく認識していることを確認できる。
Content Addressable Storage (CAS) ― Gitの肝
Gitはコミットやファイルを「オブジェクト」として保存し、その実体は SHA-1 ハッシュで所在が決まる。たとえばコミット 84eae65b...
は次のパスに格納される。
.git/objects/84/eae65b6780129486768e6497736c38bfdf9b3d
オブジェクトのフォーマットは
<型> <サイズ>\0<内容>
であり、コミットならば commit 1136\0...
という構造だ。
コミット はツリーへのポインタを含み、ツリー はファイル名・モード・ファイルハッシュ(blob)を列挙する。以下はツリーの一部を zlib 解凍して覗いた例である。
100644 .gitignore␀d6 20 48 19 40 ...
ハッシュを手で計算し、最初のコミットを鍛造する
Blob を作成
$ echo -e "blob 94\x00$(cat haiku.txt)" | sha1sum e5d59773e77daf9f9b9129781ca77d475a451831 -
ツリー を組み立て
$ printf "tree 37\x00100644 haiku.txt\x00<20byte blob>" | sha1sum 4aff48f6390a65b88d343ea5d23c03007646b5c2 -
コミット を生成し、署名付きで保存
tree 4aff48f6390a65b88d343ea5d23c03007646b5c2 author Drew Silcock <...> 1752659127 +0100 committer Drew Silcock <...> 1752659127 +0100 gpgsig -----BEGIN PGP SIGNATURE----- ... -----END PGP SIGNATURE----- Initial artisanal commit.
参照 (
refs/heads/main
) をコミットハッシュで更新し、git log --show-signature
で結果を確認。
手作業ならではの落とし穴と診断
.git/objects
に壊れたファイルを置くとerror: bad tree object HEAD
が発生する。git fsck --full
はオブジェクト整合性を検査し、問題箇所を示してくれる。
まとめ
Git の設計は、SHA-1 を鍵とする単純なオブジェクトストアと参照ファイルだけで成り立っている。高機能に見える差分表示やブランチ操作も、このシンプルな基盤の上に構築された “薄い磁器” にすぎない。内部構造を一度でも手で組み立ててみれば、Git が「魔法」ではなく理詰めの道具であることが腑に落ちるはずだ。
詳細は[Artisanal Handcrafted Git Repositories」を参照していただきたい。