shop.oreilly.com
Git Concepts at Work
- 実際にGitリポジトリを作って内部表現を詳細に見てみる
Inside the .git Diretory
git init
find .
.
./.git
./.git/HEAD
./.git/branches
./.git/config
./.git/description
./.git/hooks
./.git/hooks/fsmonitor-watchman.sample
./.git/hooks/update.sample
./.git/hooks/pre-applypatch.sample
./.git/hooks/pre-push.sample
./.git/hooks/pre-receive.sample
./.git/hooks/applypatch-msg.sample
./.git/hooks/pre-commit.sample
./.git/hooks/prepare-commit-msg.sample
./.git/hooks/commit-msg.sample
./.git/hooks/post-update.sample
./.git/hooks/pre-rebase.sample
./.git/objects
./.git/objects/pack
./.git/objects/info
./.git/info
./.git/info/exclude
./.git/refs
./.git/refs/tags
./.git/refs/heads
- 中身はGitのバージョン依存
- 例
.git/hooks/*.sample
の.sample
サフィックスは新しいバージョンでは無くなっていたりするらしい
git version 2.17.1
ではまだあるみたい
- オブジェクトストアははじめ空っぽ
find .git/objects/
.git/objects/
.git/objects/pack
.git/objects/info
echo "hello world" > hello.txt
git add hello.txt
- 【補】addするだけでオブジェクトストアに格納される
- 完全に同じファイル内容ならばSHA1値も同じ
find .git/objects
.git/objects
.git/objects/3b
.git/objects/3b/18e512dba79e4c8300dd08aeb37f8e728b8dad
.git/objects/pack
.git/objects/info
- これ
3b18e512dba79e4c8300dd08aeb37f8e728b8dad
Objects, Hashes, and Blobs
- SHA1ハッシュ(160bits)の40桁16進数表記の名前でオブジェクトを保存
- 効率のために頭2桁=先頭1バイトでディレクトリを切っている
- 256通りの一様分布パーティショニング
- オブジェクトの読み込み:
git cat-file
サブコマンド
git cat-file -p 3b18e512dba79e4c8300dd08aeb37f8e728b8dad
hello world
- 40桁全部手入力するのは酷
- 前方一致で特定できればそれをルックアップしてくれる
git rev-parse 3b18
3b18e512dba79e4c8300dd08aeb37f8e728b8dad
git rev-parse 3b1
fatal: ambiguous argument '3b1': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'
~/learn/git/sandbox $
How Do We Know a SHA1 Hash Is Unique?
- ぶつかる可能性は0ではないが、実用上心配する必要はない
- SHA1は暗号学的ハッシュ関数
- 偶然おこることは?
- 280個くらいオブジェクトを作れば衝突確率は有意になってくる
- Bruce Schneierを読め
Files and Trees
- blobがオブジェクトストアのなかに安置されていることはわかった
- ファイル名はどこ?
- treeで追跡している
git add
,git rm
, git mv
ではまだtreeオブジェクトはできない
git ls-files -s
100644 3b18e512dba79e4c8300dd08aeb37f8e728b8dad 0 hello.txt
git write-tree
68aba62e560c0ebc3396e8ae9335232cd93a3f60
find .git/objects
.git/objects
.git/objects/3b
.git/objects/3b/18e512dba79e4c8300dd08aeb37f8e728b8dad
.git/objects/pack
.git/objects/info
+ .git/objects/68
+ .git/objects/68/aba62e560c0ebc3396e8ae9335232cd93a3f60
68aba6...
がtree
- blobと同じオブジェクトなので、同じ低レベルコマンドで中身を見れる
git cat-file -p 68aba6
100644 blob 3b18e512dba79e4c8300dd08aeb37f8e728b8dad hello.txt
- わかりやすい
- ファイル属性(8進数)
- 参照しているオブジェクトの種類
- 参照しているオブジェクトのSHA1
- blobに紐付いているファイル名
A Note on Git's Use of SHA1
- 再現性
- 同じtreeをいくつも再生成するような無駄なことはしない
git write-tree
68aba62e560c0ebc3396e8ae9335232cd93a3f60
git write-tree
68aba62e560c0ebc3396e8ae9335232cd93a3f60
git write-tree
68aba62e560c0ebc3396e8ae9335232cd93a3f60
- ハッシュ関数は純粋関数
- 衝突はせず、オブジェクトと1対1とみなせる
- 同じハッシュ値のオブジェクトがあれば、それは同じ内容のオブジェクト
- 同じハッシュ値のオブジェクトがなければ、同じ内容のオブジェクトはない
- commitは、それ以下の全データ構造の状態を一意に特定する
- commitは親commitとtreeを参照する
- 再帰的
Tree Hierarchies
mkdir subdir
cp hello.txt subdir/
git add subdir/hello.txt
git write-tree
492413269336d21fac079d4a4672e55d5d2147ac
git cat-file -p 492413269
100644 blob 3b18e512dba79e4c8300dd08aeb37f8e728b8dad hello.txt
040000 tree 68aba62e560c0ebc3396e8ae9335232cd93a3f60 subdir
- 見覚えのあるSHA1値
68aba6...
- オブジェクト一覧
find .git/objects
.git/objects
+ .git/objects/49
+ .git/objects/49/2413269336d21fac079d4a4672e55d5d2147ac
.git/objects/3b
.git/objects/3b/18e512dba79e4c8300dd08aeb37f8e728b8dad
.git/objects/pack
.git/objects/info
.git/objects/68
.git/objects/68/aba62e560c0ebc3396e8ae9335232cd93a3f60
Commits
object |
(低レベル)コマンド |
blob |
git add |
tree |
git write-tree |
commit |
git commit-tree |
echo -n "Commit a file that says hello\n" \
| git commit-tree 4924132
- commitが指すtreeを指定し、コミットメッセージを流し込む
ef7baf4adb968812217b4e81b58577ca51bedb71
- 完全に同一のコミットにはならないので、SHA1値は毎回変わる
- 指しているtreeは完全に同一
- commitオブジェクトとtreeオブジェクトとが分離されている理由
- 同一のtreeを複数の異なるcommitが指したりする
- 【補】
merge
時に--no-ff
でわざとmerge commitを刻んだりするやつ
- commitオブジェクトの確認
git cat-file -p ef7baf4a
tree 492413269336d21fac079d4a4672e55d5d2147ac
author Daiki Horiyama <d19921207@gmail.com> 1572018647 +0900
committer Daiki Horiyama <d19921207@gmail.com> 1572018647 +0900
Commit a file that says hello\n
- 実生活では上記低レベルコマンドは使わずに
git commit
する
- commitはオブジェクトだが、treeとは完全に異なる構造
- tree: 木
- commit: 一般には木ではないグラフ
- 2種類ある
- lightweight
- 単にcommitを参照する
- リポジトリプライベート
- annotated
- commitに名前をつけるうえでは同じように扱える
- が、基本的にはGitコマンドはannotated tagにしかはたらかない
git tag -m "Tag version 1.0" V1.0 ef7baf
git rev-parse V1.0
b347bc62dcc80376c4a926d9dba5ebe11e013510
git cat-file -p b347bc
object ef7baf4adb968812217b4e81b58577ca51bedb71
type commit
tag V1.0
tagger Daiki Horiyama <xxxxxxxxx@gmail.com> 1572019505 +0900
Tag version 1.0
- 格納される情報
- ログメッセージ(
-m
オプションで指定したもの)
- tagger
- GPG署名(今回は指定していない)
- 参照するcommitのSHA1値(
ef7baf
)
- タグはcommitを指し、commitはtreeを指すので、tree以下の全ファイルに適用される
英語
- chancy
- bank on
- ensconce
- encompass