$30 off During Our Annual Pro Sale. View Details »

たぶんもう怖くないGit/maybe-not-afraid-of-git-anymore

marchin
February 10, 2022

 たぶんもう怖くないGit/maybe-not-afraid-of-git-anymore

marchin

February 10, 2022
Tweet

More Decks by marchin

Other Decks in Technology

Transcript

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  14. 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のオブジェクトの追加、ポストイットの移動を行ってい
    るだけ。

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  18. gitオブジェクト

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  48. 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オブジェ
    クトを作ってみる。

    View Slide

  49. 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
    コンテンツ

    View Slide

  50. 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
    コンテンツ
    ヘッダー

    View Slide

  51. 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
    ヘッダー
    コンテンツ
    ヘッダー+コンテンツ

    View Slide

  52. 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
    ヘッダー
    コンテンツ
    ヘッダー+コンテンツ
    ハッシュ値

    View Slide

  53. 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オブジェクト

    View Slide

  54. 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オブジェクト、同じハッシュ値になる。

    View Slide

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

    View Slide

  56. リファレンス

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  81. HEADの現在地

    View Slide

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

    View Slide

  83. View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  87. View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  91. 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
    ※コンフリクトは起きない前提です

    View Slide

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

    View Slide

  93. git管理開始

    View Slide

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

    View Slide

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

    View Slide

  96. hello1.txtを作成

    View Slide

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

    View Slide

  98. addしてステージングす

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  103. commitしてみる。

    View Slide

  104. Gitオブジェクトが増
    える

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  111. ディレクトリを作成。

    View Slide

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

    View Slide

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

    View Slide

  114. 両方ともaddする。

    View Slide

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

    View Slide

  116. DAGはここができてい
    る。

    View Slide

  117. コミットしてみる。

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    gitオブジェクトは、圧縮されて
    いるし、中身が同じ別の gitオ
    ブジェクトは作成されないの
    で、データ量の削減にもなって
    いる。

    View Slide

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

    View Slide

  127. ブランチを作成する。

    View Slide

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

    View Slide

  129. hello1.txtを修正してみる。

    View Slide

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

    View Slide

  131. addして、commitする。

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  162. 参考文献
    - 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/

    View Slide

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

    View Slide