Dive into .git

 2012-05-24 西尾泰和
about

• このスライドは社内勉強会で10分間で
 gitの中身を見てみるデモをするために
 アンチョコとして作られたものです。

• 1ページ16スライドで印刷すると1枚で
 収まるのでちょうどいいかと思います。
Gitよくわからん?

• 「Gitのいろんな概念が難しい」?
• じゃあ概念は置いといて、
 「物理的にはどうなってんの?」
 を確認してみよう!

• Gitがどんなものかイメージしやすくなれば幸い
実験用のリポジトリを作る
$ mkdir test   種も仕掛けもないただの
$ cd test      空のディレクトリを作る
$ ls -a
.    ..

$ git init
Initialized empty Git repository
in .../test/.git/ ←できた!

                  $ git init test でもOK
$ ls -a
.    ..   .git

                 リポジトリができた!
中身を見てみよう
$ cd .git
$ tree
.
|-- HEAD
|-- config
|-- description
|-- hooks
|-- info
|   `-- exclude
|-- objects
|   |-- info
|   `-- pack
`-- refs
    |-- heads
    `-- tags      hooksの中身は省略した
コミットしたら
         何が変わる?

$ cd ..
$ touch README
$ git add README
$ git commit -m “initial commit”
[master (root-commit) 4dd66d3]
initial commit
objectsが増えた
$ tree .git/objects
.git/objects
|-- 4d
|   `-- d66d3a32a66f3578317717ccfb18
|-- 54
|   `-- 3b9bebdc6bd5c4b22136034a95dd
|-- e6
|   `-- 9de29bb2d1d6434b8b29ae775ad8
|-- info
`-- pack
              長いファイル名の末尾は省略した
            他にも変わる部分があるが今回は割愛
中を見てみよう!
   表示スクリプトを作る
$ cat > show.py
#!/usr/bin/env python
import sys
import zlib

data = file(sys.argv[1], "rb").read()
data = zlib.decompress(data)
print repr(data)

   以下ではshow.py。chmod +xを忘れずに
Commitの中身
$ ./show.py .git/objects/4d/d6...
'commit 201x00
tree 543b...n
author NISHIO Hirokazu <...> 1337655529 +0900n
committer NISHIO Hirokazu <...> 1337655529 +0900n
n
initial commitn'


 ハッシュ値はコミット時のメッセージに表示されている
                               適当に改行を入れた
                                tree 543bに注目
Treeの中身
$ ./show.py 54/3b...
'tree 34x00
100644 READMEx00
xe6x9dxe2x9b...'


                適当に改行を入れた
                  e69bに注目
Blobの中身


$ ./show.py e6/9d...
'blob 0x00'
           これがREADMEの中身
           今は空なのでサイズが0
            x00の後に何もない
ファイル名

$ python -c “import hashlib;
hashlib.sha1('blob 0x00').hexdigest()”
'e69de29b...'

         実は中身のSHA1ハッシュ!
まとめ
• リポジトリは.git/の中に入っている
• .git/objects/に、sha1ハッシュを名前にし、
 値をzlibで圧縮して、いろいろ入っている

• 「いろいろ」の中にはcommitオブジェクト、
 treeオブジェクト、blobオブジェクト

• 今回はtagやrefsの話は割愛(次回?)
やってみよう
• READMEを編集してどう変わるか観察しよう
• 新しいcommitオブジェクトには
 「parent <ハッシュ値>」の行がある

• 新しいblobにはREADMEの内容が入っている
• 新しいファイルを追加してみよう。Treeはどう
 変わる?

• ファイルに追記したら?blobは差分?全体?
おまけ


• git show --format=rawがぜんぜんraw
 じゃなくて使いものにならない話
中を見てみよう
$ git show --format=raw 4dd6
commit 4dd66d3a32a66f3578317717ccfb1876d43034ea
tree 543b9bebdc6bd5c4b22136034a95dd097a57d3dd
author NISHIO Hirokazu <...> 1337138246 +0900
committer NISHIO Hirokazu <...> 1337138246 +0900

    initial commit

diff --git a/README b/README
new file mode 100644
index 0000000..e69de29


                          メールアドレスは省略した
Treeの中身

$ git show --format=raw 543b
tree 543b

README
Blobの中身


$ git show --format=raw e69d

        何も表示されない
おかしい
$ git show --format=raw 543b
tree 543b

README
          これの中身がe69d
         だという情報はどこ?


         というわけで表示スクリプトを作った
Q&A
• Q: スクリプト作らなくてもgunzipとかで解凍す
 れば良いのでは?

• A: zlibで圧縮されてはいるが、zipファイルとして
 validなフォーマットにはなっていないので解凍で
 きなかった。もしもっと手軽な方法があれば教え
 て下さい。

Dive into .git 日本語版