Slide 1

Slide 1 text

たぶんもう怖くないGit ~Git内部の仕組み~

Slide 2

Slide 2 text

自己紹介 - 名前: 阿部 真之 - 仕事: 主にAndroidエンジニア - 最近はサーバサイド Kotlinの仕事も始めました - 趣味 - コーヒー、ビール、アニメ、ゲーム、読書、 etc… - Twitter: @marchin_1989

Slide 3

Slide 3 text

本日はqiitaで書いた記事の内容です

Slide 4

Slide 4 text

アジェンダ - バージョン管理システム(VCS)について - Gitオブジェクトとリファレンス - Gitオブジェクトとリファレンスの視点でgit操作をみる

Slide 5

Slide 5 text

ここで話さないこと - コミット間の差分の検出方法 - gitの設定

Slide 6

Slide 6 text

ここで話さないこと - コミット間の差分の検出方法 - gitの設定 => gitコマンドを打って、gitプログラムの処理が終わった後の、 gitのデータの最終結果にフォーカスする

Slide 7

Slide 7 text

そもそもバージョン管理システム(VCS) - 集中型 - CVS, Subversion, SVN - みんなで1つのリポジトリにネットワーク接続。 - 最新のソースコードを手元に持ってきて編集。 - 各自が中央のリポジトリに変更を直接反映する。 - 変更履歴を見たい場合は、中央リポジトリにアクセスする必要がある。 - 分散型(DVCS) - Git - 各自がリポジトリを持つ。 - リモートリポジトリにネットワーク接続不要 で、 各自のリポジトリで変更、履歴の確認ができる。 - 他の人に影響を与えず、各自のリポジトリで変更を反映できる。 - 例: 各自のローカルマシン内にリポジトリがある。 - リモートリポジトリに、後からまとめて変更を反映。 自分で送りたいものだけ共有できる。 集中型 分散型

Slide 8

Slide 8 text

Git - オープンソースの分散型バージョン管理システム。 - リーナス・トーバルズによって開発。 - Linuxカーネルの効率的な開発のために作られた。 - gitのソースコードもgitで管理されてる。 - 2005年12月21日リリース。

Slide 9

Slide 9 text

よくある疑問 - どうやってGitは履歴を管理してるんだ? - よくブランチみたいな複雑そうなものうまく動いてんな。 - ブランチ is 何?枝なの? - HEAD is 何? - detached headみたいなログが出たけど、これなに?

Slide 10

Slide 10 text

よくある疑問 - どうやってGitは履歴を管理してるんだ? - よくブランチみたいな複雑そうなものうまく動いてんな。 - ブランチ is 何?枝なの? - HEAD is 何? - detached headみたいなログが出たけど、これなに? => 毎日Git使ってるのに、よくわかってない。。。

Slide 11

Slide 11 text

git内部の仕組みを知っていると役立つこと - gitのコマンドを間違って実行してしまった時の対処 - 例 - 作業していたブランチを消してしまった。。 - revert、reset、rebaseなど使ったけど、期待した状態にならなかった。。

Slide 12

Slide 12 text

git内部の仕組みを知っていると役立つこと - gitのコマンドを間違って実行してしまった時の対処 - 例 - 作業していたブランチを消してしまった。。 - revert、reset、rebaseなど使ったけど、期待した状態にならなかった。。 => 戻したいけど、毎回なんとなくググってやってる。 合ってるのかよくわからないけど、okにしてませんか?

Slide 13

Slide 13 text

git内部の仕組みを知っていると役立つこと - gitのコマンドを間違って実行してしまった時の対処 - 例 - 作業していたブランチを消してしまった。。 - revert、reset、rebaseなど使ったけど、期待した状態にならなかった。。 => 戻したいけど、毎回なんとなくググってやってる。 合ってるのかよくわからないけど、okにしてませんか? => git内部の仕組みを知ることで、gitコマンドが何をやっているのか理解しやすい

Slide 14

Slide 14 text

gitのデータ保存の仕組み(いきなり結論) - gitは、オブジェクトモデルでデータを保存している。 - gitオブジェクトの集まりで、単なるDAG(有向非巡回グラフ)とポストイットで履歴を管理 している。 - DAG: Directed Acyclic Graph(有向非巡回グラフ) - https://ja.wikipedia.org/wiki/%E6%9C%89%E5%90%91%E9%9D%9E%E5%B7%A1%E5%9B %9E%E3%82%B0%E3%83%A9%E3%83%95 - コミットは差分ではなく、スナップショット。 - gitの数あるコマンドは、DAGのオブジェクトの追加、ポストイットの移動を行ってい るだけ。

Slide 15

Slide 15 text

キーワード - Gitオブジェクト - blob, tree, commit, tag - リファレンス - branch, HEAD, tag

Slide 16

Slide 16 text

キーワード - Gitオブジェクト - blob, tree, commit, tag - リファレンス - branch, HEAD, tag => Gitオブジェクト と リファレンスの存在を強く意識すると理解しやすいです。

Slide 17

Slide 17 text

ここからの説明の順番 1. Gitオブジェクトとリファレンスの説明 2. DAG(非巡回有向グラフ)全体を眺めて、gitコマンドでDAGがどうなるかまずざっくり 説明 3. さらにより詳しく、gitコマンドによって、Gitオブジェクトが作成される様子や、リファレ ンスが作成されたり、移動する様子をみる

Slide 18

Slide 18 text

gitオブジェクト

Slide 19

Slide 19 text

gitオブジェクト(objects) - すべてzlibライブラリで可逆圧縮されたもの。 - SHA-1ハッシュによって識別子がついている。 - オブジェクトは4種類。 - 「.git/objects」ディレクトリを見ると確認できる。 - イミュータブル。一度作られたらなかなか消えない。 ※アノテーションタグ hash: e732... hash: 4g35... hash: k35g... hash: 245f...

Slide 20

Slide 20 text

gitオブジェクト(objects) - すべてzlibライブラリで可逆圧縮されたもの。 - SHA-1ハッシュによって識別子がついている。 - オブジェクトは4種類。 - 「.git/objects」ディレクトリを見ると確認できる。 - イミュータブル。一度作られたらなかなか消えない。 ※アノテーションタグ hash: e732... hash: 4g35... hash: k35g... hash: 245f... リファレンスにも「tag」があ る。ややこしいので、リファレ ンスの時に一緒に見る。

Slide 21

Slide 21 text

gitオブジェクトは「.git/objects」以下にある

Slide 22

Slide 22 text

blobオブジェクト - ファイルデータ(テキストデータ、画像etc)の中身そのもの。 - ファイル名などの情報は含まれていない。

Slide 23

Slide 23 text

blobオブジェクト - ファイルデータ(テキストデータ、画像etc)の中身そのもの。 - ファイル名などの情報は含まれていない。 gitオブジェクトは、可逆圧縮されているので、普通 にファイルを開いても意味がない。 gitのコマンドで、gitオブジェクトの内容を表示するも のがある。 git cat-file -p

Slide 24

Slide 24 text

blobオブジェクト - ファイルデータ(テキストデータ、画像etc)の中身そのもの。 - ファイル名などの情報は含まれていない。 この出力が、blobオブジェクトの内容。 docker-compose.ymlの中身そのもの。 この出力に「docker-compose.yml」のファ イル名の情報はどこにもない。

Slide 25

Slide 25 text

treeオブジェクト - ディレクトリを表す。 - ファイル名、blobオブジェクト or 別のtreeオブジェクトへの参照を持っている。

Slide 26

Slide 26 text

treeオブジェクト - ディレクトリを表す。 - ファイル名、blobオブジェクト or 別のtreeオブジェクトへの参照を持っている。 5r8d20 また、git cat-fileコマンドで、 内容を見てみる。

Slide 27

Slide 27 text

treeオブジェクト - ディレクトリを表す。 - ファイル名、blobオブジェクト or 別のtreeオブジェクトへの参照を持っている。 5r8d20 これがtreeオブジェクトの内 容。

Slide 28

Slide 28 text

treeオブジェクト - ディレクトリを表す。 - ファイル名、blobオブジェクト or 別のtreeオブジェクトへの参照を持っている。 この一行に注目してみる。 5r8d20

Slide 29

Slide 29 text

treeオブジェクト - ディレクトリを表す。 - ファイル名、blobオブジェクト or 別のtreeオブジェクトへの参照を持っている。 gitオブジェクトのタイプ blobもしくは、tree。 5r8d20

Slide 30

Slide 30 text

treeオブジェクト - ディレクトリを表す。 - ファイル名、blobオブジェクト or 別のtreeオブジェクトへの参照を持っている。 ディレクトリ内のgitオブジェクトのハッシュ 値。 5r8d20

Slide 31

Slide 31 text

treeオブジェクト - ディレクトリを表す。 - ファイル名、blobオブジェクト or 別のtreeオブジェクトへの参照を持っている。 ファイル名やディレクトリ名。 5r8d20

Slide 32

Slide 32 text

treeオブジェクト - ディレクトリを表す。 - ファイル名、blobオブジェクト or 別のtreeオブジェクトへの参照を持っている。 5r8d20 0be9e3 c5ac20 93db38 Procfile README.md app この3つを、図に当てはめてみると ...

Slide 33

Slide 33 text

treeオブジェクト - ディレクトリを表す。 - ファイル名、blobオブジェクト or 別のtreeオブジェクトへの参照を持っている。 5r8d20 0be9e3 c5ac20 93db38 Procfile README.md app 参照先のgitオブジェクトと、タイプ、それぞ れのファイル名(ディレクトリ名)を保持して いることわかる。

Slide 34

Slide 34 text

treeオブジェクト - ディレクトリを表す。 - ファイル名、blobオブジェクト or 別のtreeオブジェクトへの参照を持っている。 以降出てくる「矢印」は参 照の方向です。

Slide 35

Slide 35 text

- 以下の情報を持つ。 - トップレベルのtreeオブジェクトへの参照 - コミットしたユーザの情報 - タイムスタンプ - コミットメッセージ - 親コミットへの参照 commitオブジェクト

Slide 36

Slide 36 text

- 以下の情報を持つ。 - トップレベルのtreeオブジェクトへの参照 - コミットしたユーザの情報 - タイムスタンプ - コミットメッセージ - 親コミットへの参照 commitオブジェクト 1aaa また、git cat-fileコマンドで、 内容を見てみる。

Slide 37

Slide 37 text

- 以下の情報を持つ。 - トップレベルのtreeオブジェクトへの参照 - コミットしたユーザの情報 - タイムスタンプ - コミットメッセージ - 親コミットへの参照 commitオブジェクト 1aaa これがcommitオブジェクトの 内容。

Slide 38

Slide 38 text

- 以下の情報を持つ。 - トップレベルのtreeオブジェクトへの参照 - コミットしたユーザの情報 - タイムスタンプ - コミットメッセージ - 親コミットへの参照 commitオブジェクト 1aaa トップレベルのtreeオブジェク トを指している。 5f8d20

Slide 39

Slide 39 text

- 以下の情報を持つ。 - トップレベルのtreeオブジェクトへの参照 - コミットしたユーザの情報 - タイムスタンプ - コミットメッセージ - 親コミットへの参照 commitオブジェクト 1aaa 親commitオブジェクトのハッ シュ値を指している。 e6c06e

Slide 40

Slide 40 text

- 以下の情報を持つ。 - トップレベルのtreeオブジェクトへの参照 - コミットしたユーザの情報 - タイムスタンプ - コミットメッセージ - 親コミットへの参照 commitオブジェクト 1aaa 親がないcommitは、initial commit。 親が2つあるのは?(問題) e6c06e

Slide 41

Slide 41 text

- 以下の情報を持つ。 - トップレベルのtreeオブジェクトへの参照 - コミットしたユーザの情報 - タイムスタンプ - コミットメッセージ - 親コミットへの参照 commitオブジェクト 1aaa 親がないcommitは、initial commit。 親が2つあるのは?(問題) e6c06e マージコミット(正解)

Slide 42

Slide 42 text

- 以下の情報を持つ。 - トップレベルのtreeオブジェクトへの参照 - コミットしたユーザの情報 - タイムスタンプ - コミットメッセージ - 親コミットへの参照 commitオブジェクト 1aaa コミットしたユーザの情報。

Slide 43

Slide 43 text

- 以下の情報を持つ。 - トップレベルのtreeオブジェクトへの参照 - コミットしたユーザの情報 - タイムスタンプ - コミットメッセージ - 親コミットへの参照 commitオブジェクト 1aaa コミットメッセージ

Slide 44

Slide 44 text

- 以下の情報を持つ。 - トップレベルのtreeオブジェクトへの参照 - コミットしたユーザの情報 - タイムスタンプ - コミットメッセージ - 親コミットへの参照 commitオブジェクト 1aaa コミットから辿れば、 この時点の プロジェクトを再構成できる。

Slide 45

Slide 45 text

つまりこういう有向非巡回グラフ

Slide 46

Slide 46 text

つまりこういう有向非巡回グラフ 矢印は依存の方向。 サイクルがない、向きを持ったグ ラフ。

Slide 47

Slide 47 text

gitオブジェクトの作り方 - ハッシュ値 - ヘッダー: オブジェクトのタイプ (blob, tree, commit) + スペース + コンテンツのサイズ + ヌルバイト - 「ヘッダー」と「コンテンツ」を連結、 sha1 hashをとったもの。 - gitオブジェクト - 「ヘッダー」と「コンテンツ」を連結、 zlibで可逆圧縮したもの。

Slide 48

Slide 48 text

gitオブジェクトの作り方 - ハッシュ値 - ヘッダー: オブジェクトのタイプ (blob, tree, commit) + スペース + コンテンツのサイズ + ヌルバイト - 「ヘッダー」と「コンテンツ」を連結、 sha1 hashをとったもの。 - gitオブジェクト - 「ヘッダー」と「コンテンツ」を連結、 zlibで可逆圧縮したもの。 出典: git documentation https://git-scm.com/book/ja/v2/Git%E3%81%AE%E5%86%85%E5%81%B4-Git%E 3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88 ハッシュ値、gitオブジェ クトを作ってみる。

Slide 49

Slide 49 text

gitオブジェクトの作り方 - ハッシュ値 - ヘッダー: オブジェクトのタイプ (blob, tree, commit) + スペース + コンテンツのサイズ + ヌルバイト - 「ヘッダー」と「コンテンツ」を連結、 sha1 hashをとったもの。 - gitオブジェクト - 「ヘッダー」と「コンテンツ」を連結、 zlibで可逆圧縮したもの。 出典: git documentation https://git-scm.com/book/ja/v2/Git%E3%81%AE%E5%86%85%E5%81%B4-Git%E 3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88 コンテンツ

Slide 50

Slide 50 text

gitオブジェクトの作り方 - ハッシュ値 - ヘッダー: オブジェクトのタイプ (blob, tree, commit) + スペース + コンテンツのサイズ + ヌルバイト - 「ヘッダー」と「コンテンツ」を連結、 sha1 hashをとったもの。 - gitオブジェクト - 「ヘッダー」と「コンテンツ」を連結、 zlibで可逆圧縮したもの。 出典: git documentation https://git-scm.com/book/ja/v2/Git%E3%81%AE%E5%86%85%E5%81%B4-Git%E 3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88 コンテンツ ヘッダー

Slide 51

Slide 51 text

gitオブジェクトの作り方 - ハッシュ値 - ヘッダー: オブジェクトのタイプ (blob, tree, commit) + スペース + コンテンツのサイズ + ヌルバイト - 「ヘッダー」と「コンテンツ」を連結、 sha1 hashをとったもの。 - gitオブジェクト - 「ヘッダー」と「コンテンツ」を連結、 zlibで可逆圧縮したもの。 出典: git documentation https://git-scm.com/book/ja/v2/Git%E3%81%AE%E5%86%85%E5%81%B4-Git%E 3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88 ヘッダー コンテンツ ヘッダー+コンテンツ

Slide 52

Slide 52 text

gitオブジェクトの作り方 - ハッシュ値 - ヘッダー: オブジェクトのタイプ (blob, tree, commit) + スペース + コンテンツのサイズ + ヌルバイト - 「ヘッダー」と「コンテンツ」を連結、 sha1 hashをとったもの。 - gitオブジェクト - 「ヘッダー」と「コンテンツ」を連結、 zlibで可逆圧縮したもの。 出典: git documentation https://git-scm.com/book/ja/v2/Git%E3%81%AE%E5%86%85%E5%81%B4-Git%E 3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88 ヘッダー コンテンツ ヘッダー+コンテンツ ハッシュ値

Slide 53

Slide 53 text

gitオブジェクトの作り方 - ハッシュ値 - ヘッダー: オブジェクトのタイプ (blob, tree, commit) + スペース + コンテンツのサイズ + ヌルバイト - 「ヘッダー」と「コンテンツ」を連結、 sha1 hashをとったもの。 - gitオブジェクト - 「ヘッダー」と「コンテンツ」を連結、 zlibで可逆圧縮したもの。 出典: git documentation https://git-scm.com/book/ja/v2/Git%E3%81%AE%E5%86%85%E5%81%B4-Git%E 3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88 ヘッダー コンテンツ ヘッダー+コンテンツ ハッシュ値 gitオブジェクト

Slide 54

Slide 54 text

gitオブジェクトの作り方 - ハッシュ値 - ヘッダー: オブジェクトのタイプ (blob, tree, commit) + スペース + コンテンツのサイズ + ヌルバイト - 「ヘッダー」と「コンテンツ」を連結、 sha1 hashをとったもの。 - gitオブジェクト - 「ヘッダー」と「コンテンツ」を連結、 zlibで可逆圧縮したもの。 出典: git documentation https://git-scm.com/book/ja/v2/Git%E3%81%AE%E5%86%85%E5%81%B4-Git%E 3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88 ヘッダー コンテンツ ヘッダー+コンテンツ ハッシュ値 gitオブジェクト 【重要】 「ヘッダー」と「コンテンツ」が同じ内容なら、 同じgitオブジェクト、同じハッシュ値になる。

Slide 55

Slide 55 text

gitオブジェクト ※アノテーションタグ hash: e732... hash: 4g35... hash: k35g... hash: 245f... 以上、gitオブジェクトでした。 タグはリファレンスで説明します。

Slide 56

Slide 56 text

リファレンス

Slide 57

Slide 57 text

リファレンス(refs) - commitオブジェクトのポインタ - commitオブジェクトのハッシュ値を指している - 簡単に指し示す先を変更できる(ポストイットみたいに) - 注意: tagはできない - 「.git/refs」や、「.git/HEAD」で確認できる。 - 3種類

Slide 58

Slide 58 text

これも 「.git」以下で確認できる。 リファレンス(refs)

Slide 59

Slide 59 text

これも 「.git」以下で確認できる。 リファレンス(refs) branch

Slide 60

Slide 60 text

これも 「.git」以下で確認できる。 リファレンス(refs) HEAD

Slide 61

Slide 61 text

これも 「.git」以下で確認できる。 リファレンス(refs) tag

Slide 62

Slide 62 text

branch - コミットを指す単純なポインタ。 - remoteのブランチも一緒。

Slide 63

Slide 63 text

branch - コミットを指す単純なポインタ。 - remoteのブランチも一緒。 「.git/refs/」以下にある。

Slide 64

Slide 64 text

branch - コミットを指す単純なポインタ。 - remoteのブランチも一緒。 ローカルのブランチ

Slide 65

Slide 65 text

branch - コミットを指す単純なポインタ。 - remoteのブランチも一緒。 remoteのブランチ

Slide 66

Slide 66 text

branch - コミットを指す単純なポインタ。 - remoteのブランチも一緒。 .git/refs/heads/main ブランチの 内容を見てみる。 ※gitオブジェクトと違い、リファレ ンスは圧縮されてない。

Slide 67

Slide 67 text

branch - コミットを指す単純なポインタ。 - remoteのブランチも一緒。 「main」ブランチは、commitの ハッシュを指している。 1aaa

Slide 68

Slide 68 text

HEAD - 現在チェックアウトしている、リファレンスを指す。 - つまり、リファレンスのリファレンス。

Slide 69

Slide 69 text

HEAD - 現在チェックアウトしている、リファレンスを指す。 - つまり、リファレンスのリファレンス。 HEADは、 「refs/heads/main」ファイ ルを指している。

Slide 70

Slide 70 text

HEAD - 現在チェックアウトしている、リファレンスを指す。 - つまり、リファレンスのリファレンス。 - 直接commitオブジェクトを参照する時もある。detached HEAD 。 リファレンスではなく、 commitオブ ジェクトを直接指せる。これが detached HEAD

Slide 71

Slide 71 text

tag - 軽量タグ - コミットを参照するリファレンス。 2種類あるが、まず1つ目。

Slide 72

Slide 72 text

tag - 軽量タグ - コミットを参照するリファレンス。 「.git/refs/tags」以下にある。 commitオブジェクトのハッシュ値を 指している。 これは軽量タグ。 aee092

Slide 73

Slide 73 text

tag - 軽量タグ - コミットを参照するリファレンス。 - アノテートタグ - tagオブジェクト(gitオブジェクト)へのリファレンス。 アノテートタグ(リファレンス)

Slide 74

Slide 74 text

tag - 軽量タグ - コミットを参照するリファレンス。 - アノテートタグ - tagオブジェクト(gitオブジェクト)へのリファレンス。 - tagオブジェクトは、commitオブジェクトへの参照を持つ。 アノテートタグ(リファレンス) tagオブジェクト(gitオブジェクト)

Slide 75

Slide 75 text

tag - 軽量タグ - コミットを参照するリファレンス。 - アノテートタグ - tagオブジェクト(gitオブジェクト)へのリファレンス。 - tagオブジェクトは、commitオブジェクトへの参照を持つ。 - 軽量タグは、コミットのハッシュしか指せないが、 tagオブジェクトでアノテート(注釈)情報を保持できる アノテートタグ(リファレンス) tagオブジェクト(gitオブジェクト)

Slide 76

Slide 76 text

tag - 軽量タグ - コミットを参照するリファレンス。 - アノテートタグ - tagオブジェクト(gitオブジェクト)へのリファレンス。 - tagオブジェクトは、commitオブジェクトへの参照を持つ。 - 軽量タグは、コミットのハッシュしか指せないが、 tagオブジェクトでアノテート(注釈)情報を保持できる アノテートタグ(リファレンス) tagオブジェクト(gitオブジェクト) a3da72 tagオブジェクトの内容(コンテンツ) 1aaa21

Slide 77

Slide 77 text

Gitオブジェクトとリファレンス - ここまでで、Gitオブジェクトとリファレンスの説明をしました

Slide 78

Slide 78 text

Gitオブジェクトとリファレンス - ここまでで、Gitオブジェクトとリファレンスの説明をしました - DAG(非巡回有向グラフ)全体を眺めて、gitコマンドでDAGがどうなるかまずざっくり 説明します

Slide 79

Slide 79 text

Gitオブジェクトとリファレンス - ここまでで、Gitオブジェクトとリファレンスの説明をしました - DAG(非巡回有向グラフ)全体を眺めて、gitコマンドでDAGがどうなるかまずざっくり 説明します - 後で、さらにより詳しく、gitコマンドによって、Gitオブジェクトが作成される様子や、リ ファレンスが作成されたり、移動する様子をみる

Slide 80

Slide 80 text

左の図の状況を考える。 いくつかコミットされ、ブランチなど のリファレンスがある。

Slide 81

Slide 81 text

HEADの現在地

Slide 82

Slide 82 text

別のブランチにチェック アウトしてみる

Slide 83

Slide 83 text

No content

Slide 84

Slide 84 text

HEADの指すブランチが 変わる。

Slide 85

Slide 85 text

HEADが指すコミットの状態(スナッ プショット)に、ワーキングディレクトリ が変更される。

Slide 86

Slide 86 text

ヘッドを元の場所に戻した。 次に、新しくコミットしてみる。

Slide 87

Slide 87 text

No content

Slide 88

Slide 88 text

新しいcommit(Gitオブジェクト) ができた。 また、mainブランチ(リファレン ス)が移動する。

Slide 89

Slide 89 text

HEADは元からmainブランチを 参照していたので、間接的に新 しいcommitを指すことになる。

Slide 90

Slide 90 text

以上、gitの内部の仕組みでした - GitオブジェクトでDAGを作り、リファレンスで参照しているだけ。 - 意外とシンプル。

Slide 91

Slide 91 text

gitオブジェクトとリファレンスの視点でgit操作を見る - gitコマンドによって、Gitオブジェクトが作成される様子や、リファレンスが作成され たり、移動する様子をみる。 - 確認するgitコマンド - git init - git add - git commit - git log - git branch - git checkout - git clone - git fetch - git merge(fast forward, non fast forward) - git rebase ※コンフリクトは起きない前提です

Slide 92

Slide 92 text

新しいまっさらなディレクトリ gitdemoを用意。 git initする。

Slide 93

Slide 93 text

git管理開始

Slide 94

Slide 94 text

.git/objects/ 以下を確認 してみる。

Slide 95

Slide 95 text

初期化した直後は、 info, packディレクトリのみ

Slide 96

Slide 96 text

hello1.txtを作成

Slide 97

Slide 97 text

中身を確認。 「hello1」1行の内容。

Slide 98

Slide 98 text

addしてステージングす る

Slide 99

Slide 99 text

再度、.git/objects/ 以下を確 認。

Slide 100

Slide 100 text

Gitオブジェクトができる。 注: ハッシュ値は先頭2文字 がディレクトリ名になる

Slide 101

Slide 101 text

git cat-fileコマンドでGitオブ ジェクトの中身を確認。 これがblobオブジェクト。 hello1.txtのコンテンツの中 身だけ持っている。

Slide 102

Slide 102 text

DAGでは、blobのみできてい る状態。

Slide 103

Slide 103 text

commitしてみる。

Slide 104

Slide 104 text

Gitオブジェクトが増 える

Slide 105

Slide 105 text

b321cd のハッシュの中身を確 認。 これはcommitオブジェクト。

Slide 106

Slide 106 text

DAGでは、このオブジェクト。

Slide 107

Slide 107 text

f97e7a のハッシュの中身を確認。 これはtreeオブジェクト。

Slide 108

Slide 108 text

DAGでは、このオブジェクト。

Slide 109

Slide 109 text

commitすると、この2つのGitオブ ジェクトできた。

Slide 110

Slide 110 text

リファレンスは、masterとHEAD ができる。 HEADはmasterを指していて、 masterはcommitオブジェクト (b321cd)を指している。

Slide 111

Slide 111 text

ディレクトリを作成。

Slide 112

Slide 112 text

dir配下に、hello2.txtと hello3.txt を作成。

Slide 113

Slide 113 text

ワーキングディレクトリ の状態。

Slide 114

Slide 114 text

両方ともaddする。

Slide 115

Slide 115 text

中身を確認。 2つblobができる。

Slide 116

Slide 116 text

DAGはここができてい る。

Slide 117

Slide 117 text

コミットしてみる。

Slide 118

Slide 118 text

この3つのGitオブジェク トができた。

Slide 119

Slide 119 text

Commitオブジェクトが作成される。 masterブランチが移動し、HEADはmasterを 指しているので、同じコミットを指す。

Slide 120

Slide 120 text

新しくできたCommitオブ ジェクトの中身を確認。

Slide 121

Slide 121 text

トップレベルのtreeを参照 している。

Slide 122

Slide 122 text

トップレベルのtreeの中身 を確認。

Slide 123

Slide 123 text

子に持つtreeとblobの参照と、 ファイル名(ディレクトリ名)を 持っている。

Slide 124

Slide 124 text

ここで注意。 ハッシュ値が同じ。実はこの2つは同じもの で、別のtreeから参照されている。 ※図(DAG)がわかりづらくなるので、あえて 分けて書いている。 変更がないgitオブジェクトは、commitの度に コピーされるわけではない。 新しいcommitでも、同じgitオブジェクトを参 照している。 =

Slide 125

Slide 125 text

ここで注意。 ハッシュ値が同じ。実はこの2つは同じもの で、別のtreeから参照されている。 ※図(DAG)がわかりづらくなるので、あえて 分けて書いている。 変更がないgitオブジェクトは、commitの度に コピーされるわけではない。 新しいcommitでも、同じgitオブジェクトを参 照している。 = gitオブジェクトは、圧縮されて いるし、中身が同じ別の gitオ ブジェクトは作成されないの で、データ量の削減にもなって いる。

Slide 126

Slide 126 text

git logで確認してみる。 右下のDAGの図とHEAD、masterブ ランチが一致している。

Slide 127

Slide 127 text

ブランチを作成する。

Slide 128

Slide 128 text

またgit logを実行してみると、「 foo」ブ ランチが作成されていて、 3498e2の ハッシュ値のcommitを指している。

Slide 129

Slide 129 text

hello1.txtを修正してみる。

Slide 130

Slide 130 text

もう1行hello1が追加された。

Slide 131

Slide 131 text

addして、commitする。

Slide 132

Slide 132 text

Commitオブジェクトが作成される。 masterブランチが移動。(HEADも追 従)

Slide 133

Slide 133 text

前のhello1.txtのコンテンツの中身を 表していたblobとは別に、新しいblob ができる。

Slide 134

Slide 134 text

このblobが編集されるわけではない。 (Gitオブジェクトはイミュータブル) 前のhello1.txtのコンテンツの中身を 表していたblobとは別に、新しいblob ができる。

Slide 135

Slide 135 text

参照していた子のblobが変更されるので、 topレベルのtreeも別に、新しいtreeオブジェ クトができる。 参照する子供のgitオブジェクトが変わると、 芋づる式に新しいgitオブジェクトができる。

Slide 136

Slide 136 text

ただし、子のtreeである、77ffd0のtree以 下は変更がないため同じものが参照され る。

Slide 137

Slide 137 text

fooブランチにチェックアウトしてみる。

Slide 138

Slide 138 text

HEADがfooブランチを指すようにな る。

Slide 139

Slide 139 text

ワーキングディレクトリは前の Commitオ ブジェクトの状態になるので、 hello1.txt が1行になっている。

Slide 140

Slide 140 text

以降のgitコマンドはDAGだけみていきます

Slide 141

Slide 141 text

git clone リモートリポジトリがある状態。

Slide 142

Slide 142 text

git clone 自分のローカルマシン。リモートリポジトリを cloneす る。

Slide 143

Slide 143 text

git clone リモートリポジトリの gitオブジェクト、 リファレンスが取得された。

Slide 144

Slide 144 text

git clone HEADが指すブランチのコミットの状態に、 作業ツリーが展開される

Slide 145

Slide 145 text

git fetch xxx xxx yyy yyy zzz リモートリポジトリの方が、 commitオブジェクトが作成さ れていて、mainブランチが進 んでいる状態。 さらにdevelopブランチが作 成されている。 git fetchしてみる。

Slide 146

Slide 146 text

git fetch xxx xxx yyy yyy zzz git fetchを行うと、リモートリ ポジトリのgitオブジェクトやリ ファレンスがローカルリポジ トリに反映される。 ただし、ローカルのbranchや HEADのリファレンスは動か ない。 zzz

Slide 147

Slide 147 text

git merge(fast-forward) HEADはmainを指している状 態。 「git merge develop」 を実行 してみる。

Slide 148

Slide 148 text

git merge(fast-forward) branchリファレンス(main)が移動 するだけ。 commitオブジェクトは作成され ない。

Slide 149

Slide 149 text

git merge(non-fast-forward) ローカルでcommitオブジェクトを作っ たとする。 リモートにはまだプッシュしておらず、 origin/mainは一つ前のコミットを指し ている。 この状態でfetchする。(まだ状況説明 が続く)

Slide 150

Slide 150 text

git merge(non-fast-forward) リモートリポジトリでコミットが作られて おり、origin/mainがそのコミットを参照 している状態になった。

Slide 151

Slide 151 text

git merge(non-fast-forward) リモートリポジトリの新しい変更 (commitオブジェクト) を、ローカルのbranchに取り込みたい。 gitオブジェクトはイミュータブルなため、我々にできる ことは、gitオブジェクトの追加か、 リファレンスの移動しかできない。 リファレンスの移動を試そうにも、つけて貼るしかでき ないため、両方の変更を取り込めない。

Slide 152

Slide 152 text

git merge(non-fast-forward) リモートリポジトリの新しい変更 (commitオブジェクト) を、ローカルのbranchに取り込みたい。 gitオブジェクトはイミュータブルなため、我々にできる ことは、gitオブジェクトの追加か、 リファレンスの移動しかできない。 リファレンスの移動を試そうにも、つけて貼るしかでき ないため、両方の変更を取り込めない。 新しいcommitオブジェクトを作 成するしかない。

Slide 153

Slide 153 text

git merge(non-fast-forward) 「git merge origin/master」を実行する。

Slide 154

Slide 154 text

git merge(non-fast-forward) 新しいcommitオブジェクトが作成される。 親commitを2つ参照しているという情報が 残る。 さらに、branch(main)が移動する。 これがnon-fast-forward merge。

Slide 155

Slide 155 text

git rebase HEADはmainにあり、mainはこの commitオブジェクトを指している。

Slide 156

Slide 156 text

git rebase origin/mainは下のcommitオブジェクトを指 している。

Slide 157

Slide 157 text

git rebase non fast forward mergeすれば変更は取り 込める。 しかし、ステッチ(縫い目)の様な状態になっ てしまうため、やりたくない。

Slide 158

Slide 158 text

git rebase 「git rebase origin/main」を実行する。

Slide 159

Slide 159 text

git rebase 新しいcommitオブジェクトができる。 branch(main)が移動する。 gitオブジェクトはイミュータブルなので、前 のcommitオブジェクトが修正されるわけで はない。

Slide 160

Slide 160 text

git rebase rebaseしても前のcommitオブジェクトは 残っている。branchを移動すれば、元の状 態に戻せる。 ※gitオブジェクトは、どこからも参照されな いと、適切なタイミングで、 gitのガベージコ レクションで消される。

Slide 161

Slide 161 text

まとめ - gitのデータストアはgitオブジェクトの集まり。 - 単なるDAGとポストイットで履歴を管理している。 - コミットは差分ではなく、スナップショット。 - commitオブジェクトから、tree, blobと参照を辿ることで、その時点の履歴を復元し ている。 - gitの数あるコマンドは、DAGのオブジェクトの追加、ポストイットの移動を行ってい るだけ。

Slide 162

Slide 162 text

参考文献 - Git for Computer Scientists - https://eagain.net/articles/git-for-computer-scientists/ - Gitの内側 - gitオブジェクト - https://git-scm.com/book/ja/v2/Git%E3%81%AE%E5%86%85%E5%81%B4-Git%E3%82%AA%E3%83%96%E3 %82%B8%E3%82%A7%E3%82%AF%E3%83%88 - Gitの参照 - https://git-scm.com/book/ja/v2/Git%E3%81%AE%E5%86%85%E5%81%B4-Git%E3%81%AE%E5%8F%82%E7 %85%A7 - コミットはスナップショットであり差分ではない - https://github.blog/jp/2021-01-06-commits-are-snapshots-not-diffs/

Slide 163

Slide 163 text

ご清聴ありがとうございました!