Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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

338259af0e093b5d91e9dc7afbcdd0d5?s=47 marchin
February 10, 2022

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

338259af0e093b5d91e9dc7afbcdd0d5?s=128

marchin

February 10, 2022
Tweet

More Decks by marchin

Other Decks in Technology

Transcript

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

  2. 自己紹介 - 名前: 阿部 真之 - 仕事: 主にAndroidエンジニア - 最近はサーバサイド

    Kotlinの仕事も始めました - 趣味 - コーヒー、ビール、アニメ、ゲーム、読書、 etc… - Twitter: @marchin_1989
  3. 本日はqiitaで書いた記事の内容です

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

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

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

  7. そもそもバージョン管理システム(VCS) - 集中型 - CVS, Subversion, SVN - みんなで1つのリポジトリにネットワーク接続。 -

    最新のソースコードを手元に持ってきて編集。 - 各自が中央のリポジトリに変更を直接反映する。 - 変更履歴を見たい場合は、中央リポジトリにアクセスする必要がある。 - 分散型(DVCS) - Git - 各自がリポジトリを持つ。 - リモートリポジトリにネットワーク接続不要 で、 各自のリポジトリで変更、履歴の確認ができる。 - 他の人に影響を与えず、各自のリポジトリで変更を反映できる。 - 例: 各自のローカルマシン内にリポジトリがある。 - リモートリポジトリに、後からまとめて変更を反映。 自分で送りたいものだけ共有できる。 集中型 分散型
  8. Git - オープンソースの分散型バージョン管理システム。 - リーナス・トーバルズによって開発。 - Linuxカーネルの効率的な開発のために作られた。 - gitのソースコードもgitで管理されてる。 -

    2005年12月21日リリース。
  9. よくある疑問 - どうやってGitは履歴を管理してるんだ? - よくブランチみたいな複雑そうなものうまく動いてんな。 - ブランチ is 何?枝なの? -

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

    HEAD is 何? - detached headみたいなログが出たけど、これなに? => 毎日Git使ってるのに、よくわかってない。。。
  11. git内部の仕組みを知っていると役立つこと - gitのコマンドを間違って実行してしまった時の対処 - 例 - 作業していたブランチを消してしまった。。 - revert、reset、rebaseなど使ったけど、期待した状態にならなかった。。

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

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

    戻したいけど、毎回なんとなくググってやってる。 合ってるのかよくわからないけど、okにしてませんか? => git内部の仕組みを知ることで、gitコマンドが何をやっているのか理解しやすい
  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のオブジェクトの追加、ポストイットの移動を行ってい るだけ。
  15. キーワード - Gitオブジェクト - blob, tree, commit, tag - リファレンス

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

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

  18. gitオブジェクト

  19. gitオブジェクト(objects) - すべてzlibライブラリで可逆圧縮されたもの。 - SHA-1ハッシュによって識別子がついている。 - オブジェクトは4種類。 - 「.git/objects」ディレクトリを見ると確認できる。 -

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

    イミュータブル。一度作られたらなかなか消えない。 ※アノテーションタグ hash: e732... hash: 4g35... hash: k35g... hash: 245f... リファレンスにも「tag」があ る。ややこしいので、リファレ ンスの時に一緒に見る。
  21. gitオブジェクトは「.git/objects」以下にある

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

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

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

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

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

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

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

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

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

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

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

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

    93db38 Procfile README.md app 参照先のgitオブジェクトと、タイプ、それぞ れのファイル名(ディレクトリ名)を保持して いることわかる。
  34. treeオブジェクト - ディレクトリを表す。 - ファイル名、blobオブジェクト or 別のtreeオブジェクトへの参照を持っている。 以降出てくる「矢印」は参 照の方向です。

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

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

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

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

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

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

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

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

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

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

    - 親コミットへの参照 commitオブジェクト 1aaa コミットから辿れば、 この時点の プロジェクトを再構成できる。
  45. つまりこういう有向非巡回グラフ

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

  47. gitオブジェクトの作り方 - ハッシュ値 - ヘッダー: オブジェクトのタイプ (blob, tree, commit) +

    スペース + コンテンツのサイズ + ヌルバイト - 「ヘッダー」と「コンテンツ」を連結、 sha1 hashをとったもの。 - gitオブジェクト - 「ヘッダー」と「コンテンツ」を連結、 zlibで可逆圧縮したもの。
  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オブジェ クトを作ってみる。
  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 コンテンツ
  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 コンテンツ ヘッダー
  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 ヘッダー コンテンツ ヘッダー+コンテンツ
  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 ヘッダー コンテンツ ヘッダー+コンテンツ ハッシュ値
  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オブジェクト
  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オブジェクト、同じハッシュ値になる。
  55. gitオブジェクト ※アノテーションタグ hash: e732... hash: 4g35... hash: k35g... hash: 245f...

    以上、gitオブジェクトでした。 タグはリファレンスで説明します。
  56. リファレンス

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

    - 「.git/refs」や、「.git/HEAD」で確認できる。 - 3種類
  58. これも 「.git」以下で確認できる。 リファレンス(refs)

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

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

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

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

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

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

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

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

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

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

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

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

    commitオブ ジェクトを直接指せる。これが detached HEAD
  71. tag - 軽量タグ - コミットを参照するリファレンス。 2種類あるが、まず1つ目。

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

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

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

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

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

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

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

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

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

  81. HEADの現在地

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

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

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

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

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

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

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

  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 ※コンフリクトは起きない前提です
  92. 新しいまっさらなディレクトリ gitdemoを用意。 git initする。

  93. git管理開始

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

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

  96. hello1.txtを作成

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

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

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

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

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

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

  103. commitしてみる。

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

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

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

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

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

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

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

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

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

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

  114. 両方ともaddする。

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

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

  117. コミットしてみる。

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

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

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

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

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

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

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

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

    gitオブジェクトは、圧縮されて いるし、中身が同じ別の gitオ ブジェクトは作成されないの で、データ量の削減にもなって いる。
  126. git logで確認してみる。 右下のDAGの図とHEAD、masterブ ランチが一致している。

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

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

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

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

  131. addして、commitする。

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

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

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

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

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

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

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

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

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

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

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

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

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

  145. git fetch xxx xxx yyy yyy zzz リモートリポジトリの方が、 commitオブジェクトが作成さ れていて、mainブランチが進

    んでいる状態。 さらにdevelopブランチが作 成されている。 git fetchしてみる。
  146. git fetch xxx xxx yyy yyy zzz git fetchを行うと、リモートリ ポジトリのgitオブジェクトやリ

    ファレンスがローカルリポジ トリに反映される。 ただし、ローカルのbranchや HEADのリファレンスは動か ない。 zzz
  147. git merge(fast-forward) HEADはmainを指している状 態。 「git merge develop」 を実行 してみる。

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

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

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

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

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

    新しいcommitオブジェクトを作 成するしかない。
  153. git merge(non-fast-forward) 「git merge origin/master」を実行する。

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

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

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

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

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

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

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

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

    ている。 - gitの数あるコマンドは、DAGのオブジェクトの追加、ポストイットの移動を行ってい るだけ。
  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/
  163. ご清聴ありがとうございました!