Dev Study
← 解説「ハッシュ値とblobの対応 — Gitはファイル名ではなく中身を保存する」に戻る

サンプルコードで身につける: ハッシュ値とblobの対応 — Gitはファイル名ではなく中身を保存する

解説で学んだ概念を、5つの具体例で確認します。素朴な例から実務寄りの例へと進みます。

1blobのバイト列を組み立てて、Gitと同じ値を出す

Gitはファイルの中身をそのままハッシュ化するのではなく、先頭に「blob 長さ\0」を付けてから計算します。このサンプルの出力 ce013625… は、実際のgit hash-objectが返す値と完全に一致します。

Python

2ヘッダを忘れると値が合わない

「中身をSHA-1にかけるだけ」だと思っていると、Gitの値と一致せず混乱します。ヘッダの有無で結果がどう変わるかを並べて確認します。ここを押さえておくと、後で自分で検算できるようになります。

Python

3ファイル名は中身に含まれない — 実機での確認

名前の違う2つのファイルに同じ内容を書いてaddすると、blobは1つしか作られません。git cat-file --batch-all-objectsでDBの中身を数えると、実際に増えていないことが分かります。

# 同じ中身のファイルを2つ作る
$ printf 'hello\n' > a.txt
$ printf 'hello\n' > backup/copy.txt

# ハッシュを比べると同じ
$ git hash-object a.txt
ce013625030ba8dba906f756967f9e9ca394464a
$ git hash-object backup/copy.txt
ce013625030ba8dba906f756967f9e9ca394464a

# 両方addしても、DBに入るblobは1つだけ
$ git add a.txt backup/copy.txt
$ git cat-file --batch-all-objects --batch-check | grep blob
ce013625030ba8dba906f756967f9e9ca394464a blob 6

# → 名前が違っても中身が同じならオブジェクトは1個

4同じファイルを100個コピーしても容量が増えない

内容ベース管理の実利が分かるサンプルです。中身が同じなら何個ファイルがあってもblobは1つなので、リポジトリはほとんど太りません。ユニークな中身の数だけがDBのサイズを決めます。

Python

5編集は上書きではなく追加

ファイルを編集しても古いblobは消えません。新しいblobが増えるだけです。だから過去のどの時点の中身も取り出せます。「Gitは差分ではなくスナップショットを持つ」の意味がここで具体化します。

# 1回目: hello を書いてコミット
$ printf 'hello\n' > a.txt && git add a.txt && git commit -m '1回目'
$ git hash-object a.txt
ce013625030ba8dba906f756967f9e9ca394464a

# 2回目: 中身を書き換えてコミット
$ printf 'hello2\n' > a.txt && git add a.txt && git commit -m '2回目'
$ git hash-object a.txt
14be0d41c639d701e0fe23e835b5fe9524b4459d

# 古いblobも残っているので、中身を取り出せる
$ git cat-file -p ce013625030ba8dba906f756967f9e9ca394464a
hello

# → オブジェクトは一度作られたら書き換えられない(追記のみ)