Gitのデータモデル

コミット周りの概念

近藤です。こんにちは。Gitは様々な利用の仕方ができますが、その基盤となるモデルは8個だけの簡単なモデルです。これらのモデルを理解していない状態でGitを利用すると、あたかもリポジトリが壊れたように見えてしまいます。Gitは難しいと言われますが、そういう感想を持つ人はGitのモデルを理解していない事が多いようです。

今回はGitを構成する中心モデルと、基本的なコマンドを実行した時のオブジェクト関係を解説します。

基本概念

Gitの基本概念は大きく2つにわかれます。

  • GitObject
  • Reference

GitObjectはGitで管理するオブジェクトです。CommitなどがGitObjectです。Gitリポジトリである.gitを開くとobjects配下にあるファイルがGitObjectです。GitObjectはそのコンテンツをハッシュ化した文字列を元に、先頭2文字で配置フォルダ、残りの文字列でファイル名です。

ReferenceCommitを参照しています。BranchなどがReferenceです。Gitリポジトリである.gitを開くと、refs配下にあるファイルがReferenceです。ReferenceのコンテンツはCommitのIDです。

それぞれの概念をまとめたのが下記のモデル図です。それぞれの概念について解説します。

Commit周りのモデル

  • Commit – コミットグラフを表現する概念です。Commitのコンテンツはcommentだけでなく、1つ前のCommit、ファイルツリーを示すTree、作成者と編集者を示すUser、作成日時、編集日時があります。rebasecherry-pickcommit --amendを行うとCommitのIDが変更になりますが、それは1つ前のCommitが変更になったり、編集日時が変更になるためです。
  • User – コミットを扱った人を表現する概念です。GitHub等ではユーザーアイコンを表示します。これはemail を使って表示しています。
  • Tree – フォルダツリーを表現する概念です。Treeは、子フォルダを示すTreeと、ファイルを示すBlobを持ちます。Treeへの参照、Blobへの参照共にnameがあります。
  • Blob – ファイルを表現する概念です。ワーキングツリーのファイルそのものがコピーされます。.gitの中には、これまで編集が少しでもあったファイルが全て入っています。
    Blobオブジェクトがファイルそのものであるため、.git/objectsの容量は大きくなりがちです。少しでも抑えるため、全く同一のコンテンツであれば新たにファイルを作らなくても済むませるためのハッシュ文字列のファイル名だったり、ファイルの圧縮だったりします。
  • Branch – ブランチそのものです。配置フォルダにより、ローカルリポジトリのブランチだったり、リモートリポジトリのブランチだったりします。.git/refs/heads配下にあるReferenceがローカルリポジトリのブランチです。.git/refs/remotes配下にあるReferenceがリモートリポジトリのブランチです。.git/HEADに書かれたrefsが現在チェックアウト中のブランチを示します。ブランチをチェックアウトしている場合、コミットがあると、コミットに追従しますが、.git/HEADから参照されたブランチのコンテンツを更新しているだけです。
  • Tag – タグそのものです。.git/refs/tags配下にあるReferenceです。

Gitは様々な機能を提供していますが、基本となるモデルはこれだけです。これらの概念を元に作成されたオブジェクトが下記のように関連しあっているのです。

コミット周りの概念(Instance)

コマンドで起きること

Gitはファイル名と配置フォルダにより、それぞれのオブジェクトを強く意味付けしています。Gitでよく使うclonefetchpush,pullの4つのコマンドで起きることをモデル図にまとめてみました。

clone

コミット周りの概念(Instance) clone

cloneを実行すると指定したリモートリポジトリからGitObjectReferenceを取得し、masterブランチをローカルブランチに作成します。

fetch

コミット周りの概念(Instance) fetch

fetchを実行すると、指定したリモートリポジトリからGitObjectReferenceを取得します。ローカルリポジトリのリモートブランチが更新されるだけです。ローカルブランチは更新されません。

push

コミット周りの概念(Instance) push

pushを実行すると、指定したリモートリポジトリにGitObjectReferenceを送信します。リモートリポジトリのブランチとローカルブランチがFast Forwardではなかった場合、エラーが返ります。push -fはFast Forwardチェックを飛ばしているだけです。 ブランチを指定している場合は、そのブランチと、ブランチに紐づくGitObjectだけ送信します。

pull

コミット周りの概念(Instance) pull

pullを実行すると、指定したリモートリポジトリからGitObjectReferenceを取得し、ローカルブランチにリモートブランチをマージします。

リポジトリの設定

リポジトリの設定は.git/configにかかれています。開いてみると下記のようなファイルになっているでしょう。


[core]
        repositoryformatversion = 0
        filemode = true
        bare = false
        logallrefupdates = true
        ignorecase = true
        precomposeunicode = false
[remote "origin"]
        url = git@github.com:ChangeVision/astah.git
        fetch = +refs/heads/*:refs/remotes/origin/*
[ branch "master" ]
        remote = origin
        merge = refs/heads/master

この例では下記の内容が記述されています。

リポジトリ自体の設定

[core]の辺りです。共用のリポジトリではないのでbare = falseとなっている、等がわかります。

リモートリポジトリの名前とURL

[remote "origin"]の辺りです。originという名前のリモートリポジトリのURLはgit@github.com:ChangeVision/astah.git、ブランチのfetch対象は+refs/heads/*:refs/remotes/origin/*と書かれてます。

ローカルブランチとリモートブランチをひもづけるUpstreamブランチ

[ branch "master"]の辺りです。masterブランチのUpstreamはoriginrefs/heads/masterと設定されています。

Gitの基本的な概念と設定についてざっくりと解説しました。案外単純だったのではないでしょうか?

こういった感じでモデル化してみると、文章だけでは見えなかった概念のつながりが見えるので、よりわかりやすかったのではないでしょうか?こういう感じで、利用しているツールの概念をモデル化してみると、よりよい使い方がわかるのでオススメです。

参考文献

GitBook

ちなみに、モデルは、astah*を使って描きました。

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s