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

commits in git

けんご
November 28, 2014

commits in git

けんご

November 28, 2014
Tweet

More Decks by けんご

Other Decks in Programming

Transcript

  1. gitのコミットの話
    内部構造から見るgitのコミット
    @tkengo
    2014-11-28

    View Slide

  2. @tkengo
    Internal of git
    最近gitの仕組みを興味本位で調べて遊んでたので
    今日はその辺の話をしてみたいと思います

    View Slide

  3. @tkengo
    Internal of git
    内部動作と実装を学ぶことは、git がどうしてこんなに便利で有効な
    のかを根本的に理解するのに重要です。
    !
    初期のgit(主として1.5以前)は、洗練されたVCS というよりもむし
    ろファイル・システムであることを(gitの特徴として)強調してお
    り、それ故に、ユーザー・インターフェイスは今よりも複雑なもので
    した。
    !
    連想記憶ファイル・システム層は驚くほど素晴らしいので、この章の
    最初にそれをカバーすることにします。
    by Pro Git

    View Slide

  4. @tkengo
    Internal of git
    つまりgitはVCSの皮を被った連想記憶ファイルシステム
    だったんだよ!

    View Slide

  5. @tkengo
    Internal of git
    ΩΩΩ < な、なんだってー
    つまりgitはVCSの皮を被った連想記憶ファイルシステム
    だったんだよ!

    View Slide

  6. @tkengo
    The body of git
    gitの本体はリポジトリのルートディレクトリにある.gitというディレクトリです。
    gitの本体
    .git/

    View Slide

  7. @tkengo
    The body of git
    .gitディレクトリの中にはいくつかのファイルとディレクトリが存在しますが、今日の説明で関係があるのはHEAD objects/ refs/ の
    3つです。
    gitの本体
    .git/
    HEAD
    objects/
    refs/
    ...

    View Slide

  8. @tkengo
    Objects in git
    gitにはblog tree commit reference head tagという6つの重要な要素があります。
    blob tree commit
    R
    reference
    H
    head tag
    愉快なgitの仲間たち

    View Slide

  9. @tkengo
    blob tree
    R
    reference
    Objects in git
    今日は主にblob tree commitについて詳しく見ていきます。reference headはちょっとだけ出てきます。tagは今回でてきません。
    commit
    H
    head tag
    今日の登場人物
    -

    View Slide

  10. @tkengo
    Objects in git
    gitはcommitしたその時点でのファイルツリーのスナップショットを持っており、スナップショットにはtreeとblobが含まれていま
    す。referenceはある特定のcommitを指しており、さらにheadは特定のreferenceを指しています。
    R
    reference
    H
    head
    blob
    tree
    commit
    tree
    blob blob
    blob
    tree
    commit
    tree
    blob blob
    blob
    tree
    commit
    tree
    blob blob
    commit
    省略...
    commit
    省略...
    commit
    省略...
    commit
    省略...
    commit
    省略...
    R
    reference
    親 親 親




    View Slide

  11. @tkengo
    Objects in git
    コミットはご存知の通りSHA1のハッシュ値を持っています。referenceは実は普段使っているブランチのことです。そしてHEADは今
    の作業位置を示しています。
    R
    feature-branch
    H
    HEAD
    blob
    tree
    6d025cd
    tree
    blob blob
    blob
    tree
    8d4a726
    tree
    blob blob
    blob
    tree
    5bd7d91
    tree
    blob blob
    96caf5f
    省略...
    31e5f34
    省略...
    edd97e4
    省略...
    fdf793c
    省略...
    1d09b9b
    省略...
    R
    master
    親 親 親




    View Slide

  12. @tkengo
    Objects in git
    実はスナップショットのtreeとblobにもそれぞれSHA1のハッシュ値がついています。
    R
    feature-branch
    H
    HEAD
    1e11458
    358a4b5
    6d025cd
    100d7a6
    8d4a726 5bd7d91 96caf5f
    省略...
    31e5f34
    省略...
    edd97e4
    省略...
    fdf793c
    省略...
    1d09b9b
    省略...
    R
    master
    親 親 親




    ddf3ec9 3d4b084
    2629bfc
    a25b132
    100d7a6
    ddf3ec9 3d4b084
    2629bfc
    2125db4
    0926525
    ddf3ec9 a214dca

    View Slide

  13. @tkengo
    Objects in git
    そしてスナップショットには、そのスナップショットを一意に識別するrootツリーがあり、commitはそのrootツリーのSHA1ハッ
    シュ値を知っています。
    H
    HEAD
    1e11458
    358a4b5
    6d025cd
    100d7a6
    8d4a726 5bd7d91 96caf5f
    省略...
    edd97e4
    省略...
    fdf793c
    省略...
    R
    master
    親 親 親 親 親
    ddf3ec9 3d4b084
    2629bfc
    a25b132
    100d7a6
    ddf3ec9 3d4b084
    2629bfc
    2125db4
    0926525
    ddf3ec9 a214dca
    rootツリー

    View Slide

  14. @tkengo
    The snapshot
    commitとtree、blobについてもう少し詳しく見てみます。この辺から少しファイルシステムっぽい話になってきます。
    blob
    tree
    commit
    tree
    blob blob

    View Slide

  15. @tkengo
    The snapshot
    treeはファイルシステム上のディレクトリに相当します。
    blob
    tree
    commit
    tree
    blob blob

    View Slide

  16. @tkengo
    The snapshot
    blobはファイルシステム上のファイルに相当します。
    blob
    tree
    commit
    tree
    blob blob

    View Slide

  17. @tkengo
    Detail of a blob
    blobは、ヘッダに対して実際のファイルの内容をくっつけたものを準備して、その内容をzlibで圧縮したものがblobの中身に、そして
    SHA1に通したものがblobのハッシュ値になります。
    ddf3ec9
    ヘッダ
    #include !
    !
    /* ϝΠϯؔ਺ */!
    int main() {!
    /* ग़ྗจࣈྻ */!
    char *str;!
    str = “Hello World!”;!
    !
    printf(str);!
    return 0;!
    }
    blob 161/0
    固定で
    “blob”
    スペース
    +
    ファイル
    ヌル
    文字
    zlib
    SHA1ハッシュ
    (161byte)

    View Slide

  18. @tkengo
    Detail of a tree
    treeもblobと同じく、ヘッダにツリーのコンテンツをくっつけたものがtreeになります。treeのコンテンツは、そのtreeに含まれる
    tree及びblobの一覧をもっています。
    9aeb4c2
    ヘッダ
    100644 tree 652e759… builtin!
    100644 blob 7ba2ba7… main.c!
    100644 blob e6c1c39… mem.c!
    ...!
    tree 177/0
    固定で
    “tree”
    スペース
    +
    (177byte)
    ヌル
    文字
    treeのコンテンツ
    zlib
    SHA1ハッシュ
    オブジェクトのモード
    オブジェクトの種類
    tree or blob
    SHA1ハッシュ値
    ファイル名 or
    ディレクトリ名
    ※実際はちょっと違うかも

    View Slide

  19. @tkengo
    Detail of a commit
    commitも同じく、ヘッダにコンテンツをくっつけたものです。commitのコンテンツは、rootツリーのSHA1ハッシュ値、親commitの
    SHA1ハッシュ値、コミットした人の情報、そしてコミットメッセージを持っています。
    ヘッダ
    tree 9aeb4c2...!
    parent 5d5de46...!
    author kengo ..!
    committer kengo ..!
    !
    first commit
    commit 180/0
    固定で
    “commit”
    スペース
    +
    ヌル
    文字
    commitのコンテンツ
    zlib
    SHA1ハッシュ
    rootツリーのSHA1ハッシュ値
    user.name と user.email の値
    コミットメッセージ
    親commitのSHA1ハッシュ値
    6d025cd
    (180byte)

    View Slide

  20. @tkengo
    Summary of snapshot
    まとめると

    View Slide

  21. @tkengo
    Summary of snapshot
    • commitはその時点のスナップショットのrootツリーを知っている
    blob
    tree
    commit
    tree
    blob blob
    ココ

    View Slide

  22. @tkengo
    Summary of snapshot
    • commitはその時点のスナップショットのrootツリーを知っている
    • commitは自分の親のcommitも知っている
    blob
    tree
    commit
    tree blob
    tree
    commit
    tree

    ココ

    View Slide

  23. @tkengo
    Summary of snapshot
    • commitはその時点のスナップショットのrootツリーを知っている
    • commitは自分の親のcommitも知っている
    • treeはそのtreeに含まれているtree及びblobを全部知っている
    blob
    tree
    commit
    tree
    ココ

    View Slide

  24. @tkengo
    Summary of snapshot
    • commitはその時点のスナップショットのrootツリーを知っている
    • commitは自分の親のcommitも知っている
    • treeはそのtreeに含まれているtree及びblobを全部知っている
    • blobはファイル内容を知っている
    ヘッダ
    #include !
    !
    /* ϝΠϯؔ਺ */!
    int main() {!
    /* ग़ྗจࣈྻ */!
    char *str;!
    str = “Hello World!”;!
    !
    printf(str);!
    return 0;!
    }
    コンテンツ
    tree 161/0
    blob

    View Slide

  25. @tkengo
    Summary of snapshot
    • commitはその時点のスナップショットのrootツリーを知っている
    • commitは自分の親のcommitも知っている
    • treeはそのtreeに含まれているtree及びblobを全部知っている
    • blobはファイル内容を知っている
    てな感じです。

    View Slide

  26. @tkengo
    Summary of snapshot
    このようにファイルやディレクトリにSHA1ハッシュをつけてblobやtreeとして管理する方法こそgitが連想記憶ファイルシステムと言
    われる所以だと言えます。それを発展させ、スナップショットとしてcommitと紐付けることでVCSとしての機能を実現しています。
    1e11458
    358a4b5
    100d7a6
    ddf3ec9 3d4b084
    358a4b5 という名前を持ったディレクトリ
    その実態は子ファイル及び子ディレクトリのSHA1ハッシュ値を並べたテキストデータを圧縮したもの
    上に同じ
    3d4b084 という名前を持ったファイル
    その実態はファイル内容そのものを圧縮したもの
    上に同じ
    スナップショットはファイルシステムに似ています

    View Slide

  27. @tkengo
    blob tree
    R
    reference
    Objects in git
    blobはファイル、treeはディレクトリ、commitはスナップショットを指し示すもの、referenceは特定のcommitを参照する、headは
    特定のreferenceを参照する、でした。
    commit
    H
    head tag
    彼らのこと少しはわかりましたか?
    -
    ファイル
    ディレクトリ
    スナップショット
    へのポインタ
    commit
    へのポインタ
    reference
    へのポインタ

    View Slide

  28. @tkengo
    Difference management
    スナップショットはわかったけど
    差分ってどこに持ってるの?

    View Slide

  29. @tkengo
    Difference management
    スナップショットはわかったけど
    差分ってどこに持ってるの?
    gitはcommit間の差分は管理していません
    実は

    View Slide

  30. @tkengo
    Difference management
    gitは、commit間の差分を比較する場合には、差分を持っていないのでどこからか差分を計算する必要があります。
    1e11458
    358a4b5
    6d025cd
    100d7a6
    ddf3ec9 3d4b084
    8d4a726
    2629bfc
    a25b132
    100d7a6
    ddf3ec9 3d4b084

    View Slide

  31. @tkengo
    Difference management
    つまりcommitが指すスナップショット同士を比較して、gitが差分を計算してくれています。
    1e11458
    358a4b5
    6d025cd
    100d7a6
    ddf3ec9 3d4b084
    8d4a726
    2629bfc
    a25b132
    100d7a6
    ddf3ec9 3d4b084
    git「あ、この
    ファイルの中身が
    変わってるな」

    View Slide

  32. @tkengo
    Save the disk space
    それにしても、このようにcommit毎にスナップショットを持っていたら大変なことにならないでしょうか。とても効率が悪そうな気
    がします。
    blob
    tree
    commit
    tree
    blob blob

    blob
    tree
    commit
    tree
    blob blob

    blob
    tree
    commit
    tree
    blob blob

    blob
    tree
    commit
    tree
    blob blob

    blob
    tree
    commit
    tree
    blob blob

    blob
    tree
    commit
    tr
    blob b
    blob
    tree
    commit
    tree
    blob blob

    View Slide

  33. @tkengo
    Save the disk space
    確かに効率は悪いですが、それはディスク容量の部分です。差分計算やcheckoutなどはスナップショットで管理した方が圧倒的に早
    いですし、ディスク容量もなるべく節約できるように工夫されています。
    blob
    tree
    commit
    tree
    blob blob

    blob
    tree
    commit
    tree
    blob blob

    blob
    tree
    commit
    tree
    blob blob

    blob
    tree
    commit
    tree
    blob blob

    blob
    tree
    commit
    tree
    blob blob

    blob
    tree
    commit
    tr
    blob b
    blob
    tree
    commit
    tree
    blob blob

    ディスク容量は確かに非効率

    View Slide

  34. @tkengo
    Save the disk space
    ディスク容量の節約について

    View Slide

  35. @tkengo
    Save the disk space
    最初の方に出てきたこの図をみて気付いた人がいたら素晴らしいですが、gitはcommit毎にスナップショットを保存するといっても、
    commit毎に全てのファイルとディレクトリを保存しているわけではありません。
    1e11458
    358a4b5
    6d025cd
    100d7a6
    8d4a726 5bd7d91
    親 親
    ddf3ec9 3d4b084
    2629bfc
    a25b132
    100d7a6
    ddf3ec9 3d4b084
    2629bfc
    2125db4
    0926525
    ddf3ec9 a214dca

    View Slide

  36. @tkengo
    Save the disk space
    この2つのcommitのスナップショットを見ていきます。
    1e11458
    358a4b5
    6d025cd
    100d7a6
    ddf3ec9 3d4b084
    8d4a726
    2629bfc
    a25b132
    100d7a6
    ddf3ec9 3d4b084
    5bd7d91
    2629bfc
    2125db4
    0926525
    ddf3ec9 a214dca

    View Slide

  37. @tkengo
    Save the disk space
    2つのスナップショットを比べると、rootツリーと、その下にある1つのblobがそれぞれ別のSHA1ハッシュ値を持っています。
    1e11458
    358a4b5
    6d025cd
    100d7a6
    ddf3ec9 3d4b084
    8d4a726
    2629bfc
    a25b132
    100d7a6
    ddf3ec9 3d4b084
    5bd7d91
    2629bfc
    2125db4
    0926525
    ddf3ec9 a214dca

    View Slide

  38. @tkengo
    Save the disk space
    もう少し詳しく見ていきます。まずはblobの方です。たとえばblobは上記のようなファイル内容を持っており、ビックリマークを2つ
    追加する変更が加えられているとします。すると 1e11458 のblobの内容が変わって新たに 2629bfc のblobが作られます。
    1e11458
    358a4b5
    6d025cd
    100d7a6
    ddf3ec9 3d4b084
    8d4a726
    2629bfc
    a25b132
    100d7a6
    ddf3ec9 3d4b084
    5bd7d91
    2629bfc
    2125db4
    0926525
    ddf3ec9 a214dca
    blob 11/0Hello World blob 13/0Hello World!!

    View Slide

  39. @tkengo
    Save the disk space
    すると、そのblobのSHA1ハッシュ値をしっている親のtreeも、子供のblobのハッシュ値を書き換えなければなりません。つまり新し
    く a25b132 のtreeが作られます。
    1e11458
    358a4b5
    6d025cd
    100d7a6
    ddf3ec9 3d4b084
    8d4a726
    2629bfc
    a25b132
    100d7a6
    ddf3ec9 3d4b084
    5bd7d91
    2629bfc
    2125db4
    0926525
    ddf3ec9 a214dca
    tree 113/0!
    100644 blob 1e11458..!
    040000 tree 100d7a6..
    tree 113/0!
    100644 blob 2629bfc..!
    040000 tree 100d7a6..

    View Slide

  40. @tkengo
    Save the disk space
    しかし変更のない他の 100d7a6 ddf3ec9 3d4b084 はそのまま再利用されています。
    1e11458
    358a4b5
    6d025cd
    100d7a6
    ddf3ec9 3d4b084
    8d4a726
    2629bfc
    a25b132
    100d7a6
    ddf3ec9 3d4b084
    5bd7d91
    2629bfc
    2125db4
    0926525
    ddf3ec9 a214dca

    View Slide

  41. @tkengo
    Save the disk space
    このような表現の方が正しそうです。commitが違っても、容量節約のためにスナップショットは同じところを指している部分があり
    ます。
    1e11458
    358a4b5
    6d025cd 8d4a726
    2629bfc
    a25b132
    5bd7d91
    2629bfc
    2125db4
    0926525
    ddf3ec9 a214dca
    100d7a6
    ddf3ec9 3d4b084

    View Slide

  42. @tkengo
    Save the disk space
    この2つのcommitのスナップショットでも、同様のことが言えます。とあるblobの変化は最終的にはスナップショットの一番上のtree
    つまりrootツリーにまで変更が伝搬していくことになります。これが各スナップショット間でrootツリーが一意になる理由です。
    1e11458
    358a4b5
    6d025cd
    100d7a6
    ddf3ec9 3d4b084
    8d4a726
    2629bfc
    a25b132
    100d7a6
    ddf3ec9 3d4b084
    5bd7d91
    2629bfc
    2125db4
    0926525
    ddf3ec9 a214dca

    View Slide

  43. @tkengo
    Internal of git
    これでgitの内部の説明は終わりです。
    !
    もう少し実感してもらうために
    最後に各オブジェクトがどんな風に
    保存されているかを見てみます。

    View Slide

  44. @tkengo
    The body of git
    最初に.gitディレクトリの中のHEAD index objects/ refs/ の3つのファイル及びディレクトリの話をしたのを覚えているでしょうか。
    HEAD
    objects/
    refs/
    ...
    .git/

    View Slide

  45. @tkengo
    The body of git
    それぞれのgitオブジェクトはこのように.gitディレクトリ以下に格納されています。
    HEAD
    objects/
    refs/
    ...
    blob tree commit
    R
    reference
    H
    head
    .git/

    View Slide

  46. @tkengo
    The body of git
    HEADはただのテキストファイルです。catなどで中身を見てみると現在のheadが指しているreferenceが書いてあります。
    HEAD
    objects/
    refs/
    ...
    .git/
    ref: refs/heads/master

    View Slide

  47. @tkengo
    The body of git
    objects/の下には、各オブジェクトのSHA1ハッシュ値の先頭2桁がディレクトリ名、残り38桁がファイル名になってファイルが格納
    されています。ディレクトリを分ける理由は1ディレクトリ中に置けるファイル数の上限を回避するためかと思います。
    HEAD
    objects/
    refs/
    ...
    .git/
    10/
    26/
    8d/
    a2/
    ...
    0d7a6...
    29bfc...
    4a726...
    5b132...
    d7644...
    ...
    100d7a6 (blob)
    2629bfc (blob)
    8d4a726 (commit)
    a25b132 (tree)
    a2d7644 (blob)

    View Slide

  48. @tkengo
    The body of git
    refs/の下にはさらにheads/ディレクトリがあり、その中にブランチ名をファイル名としたファイルがあります。中身はただのテキス
    トファイルで、そのブランチが指し示しているcommitのSHA1ハッシュ値が書き込まれています。
    HEAD
    objects/
    refs/
    ...
    .git/
    master
    feature-branch
    ...
    heads/

    View Slide

  49. @tkengo
    The body of git
    もう一度HEADの中身を確認してみます。refs/heads/masterと書かれていましたね。これはつまりrefs/以下のディレクトリを指して
    たってことですね。
    HEAD
    objects/
    refs/
    ...
    .git/
    master
    feature-branch
    ...
    heads/
    ref: refs/heads/master

    View Slide

  50. @tkengo
    Internal of git
    gitのこと少しでもわかったでしょうか。

    View Slide

  51. おわり

    View Slide