[git] Gitの内部(ツリーオブジェクト)
こんにちは、@yoheiMuneです。
今回は、Gitのデータ格納方法のうち、ツリーオブジェクトについてブログを書きたいと思います。
Gitの内部(はじめに) Gitの内部(データ格納 - データオブジェクト)
上記の内容から、
前回の記事では、
現在の状態は、以下の通りです。
この状態で、ツリーオブジェクトを作成しましょう。
それでは続いて、もう1つツリーオブジェクトを作りましょう。
ここでは、現在ステージングされていない"versio 2"のファイルをステージングエリアに追加します。
それではここで、最初のツリー(
最後までご覧頂きましてありがとうございました。
今回は、Gitのデータ格納方法のうち、ツリーオブジェクトについてブログを書きたいと思います。
Special Thanks to http://flic.kr/p/kxC7Bm
この記事を読む前に
この記事は、Gitの内部について書かれた、以下の記事の続きとして書いています。 以下の記事を先にお読み頂くと、今回の記事をより理解頂けるのではないかと思います。Gitの内部(はじめに) Gitの内部(データ格納 - データオブジェクト)
この記事で伝えたいこと
この記事の目的は、Gitのツリーオブジェクトとは何か、を解説することです。 ツリーオブジェクトの中身を見る、ツリーオブジェクトを作成するという内容を通して、ツリーオブジェクトに対する知識を深められると思います。ツリーオブジェクト
以下の内容は、Pro Gitを参照して、記載しています。
ツリーオブジェクトは、ステージングされたデータ関する情報を保持するオブジェクトです。 ツリーオブジェクトは、ステージングされたファイルの名前やそのハッシュ値などを保持します。 ファイルシステムに例えると、データオブジェクトがファイルであり、ツリーオブジェクトがディレクトリのようなものです。ツリーオブジェクトの中身を見る
それではまずは、ツリーオブジェクトの中身を見てみましょう。 以下では、masterブランチ上での最後のコミットが参照しているツリーオブジェクトを表示しています。$ git cat-file -p master^{tree} 100644 blob a906cb2a4a904a152e80877d4088654daad0c859 README 100644 blob 8f94139338f9404f26296befa88755fc2598c289 Rakefile 040000 tree 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0 libこのツリーオブジェクトには、2つのデータオブジェクトと1つのツリーオブジェクトが含まれていることが分かります。 それぞれのデータに対して、以下の情報が格納されています。
- モード
100644
などの数値部分。そのデータがどのようなものかを示す。例えば、100644
はファイル、100755
は実行可能ファイル、120000
はシンボリックリンクを表します。- データ種類
blob
などの表示部分。Gitにおけるデータの種類を示します。- ハッシュ値
- そのデータを参照するためのSHA-1で作成した40文字のハッシュ値
- 名前
README
などの表示部分。ファイル名やディレクトリ名を示します。
lib
というツリーオブジェクトが含まれています。その内容を表示してみましょう。$ git cat-file -p 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0 100644 blob 47c6340d6459e05787f644c2447d2595f5d3a54b simplegit.rb
lib
ツリーオブジェクトには、1つのBlogデータが含まれていることが分かります。上記の内容から、
master^{tree}
の中身を、以下のように図示することができます。引用:http://git-scm.com/book/en/Git-Internals-Git-Objects
以上が、ツリーオブジェクトが保持する内容です。ツリーオブジェクト作成する
それでは続いて、ツリーオブジェクトを作成してみましょう。 Gitでは通常、git add
などのタイミングでツリーオブジェクトが作成されます。
しかしここでは、ツリーオブジェクトをより理解するために、
git update-index
やgit write-tree
などの内部コマンドを使って、ツリーオブジェクトを作成してみましょう。以降で利用するレポジトリは、前回の記事で作成したレポジトリを利用しています。
前回の記事では、
test.txt
というファイルで"version 1"
と"version 2"
という2つのバージョンのファイルを作成しました。$ find .git/objects -type f .git/objects/83/baae61804e65cc73a7201a7252750c76066a30 # test.txtのバージョン1 .git/objects/1f/7a7a472abf3dd9643fd615f6da379c4acb3e3a # test.txtのバージョン2 # 他のハッシュは省略しています $ git cat-file -p 83baae61804e65cc73a7201a7252750c76066a30 version 1 $ git cat-file -p 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a version 2最初に、
"version 1"
のtest.txtのみを持つツリーオブジェクトを作成してみたいと思います。
まずは、git update-index
を使って対象ファイルをステージング状態にします。git update-index --add --cacheinfo 100644 83baae61804e65cc73a7201a7252750c76066a30 test.txt
--add
オプションは、最初のバージョンのtest.txtが新規ファイルでステージングエリアに存在しないため、付ける必要があるオプションです。
--cacheinfo
は、ディレクトリには存在せずデータベースにのみ存在する(ディレクトリにはtest.txtという同名のファイルがありますが、内容は"version 2")ため、データベースからステージングに追加するために必要なオプションです。
100644
は、データの種類を指定しています。現在の状態は、以下の通りです。
$ git status # On branch master # # Initial commit # # Changes to be committed: # (use "git rm --cached <file>..." to unstage) # # new file: test.txt #ステージングしたファイル # # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: test.txt #前回作成した"version 2"のファイル #ステージングされているtest.txtが、
git update-index
で追加したもので、ステージングされていないファイルが、前回の最後に作成したtest.txtです。この状態で、ツリーオブジェクトを作成しましょう。
git write-tree
という内部コマンドを利用します。$ git write-tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579これでツリーオブジェクトが作成されました。中身を確認しましょう。
$ git cat-file -p d8329fc1cc938780ffdd9f94e0d364e0ea74f579 100644 blob 83baae61804e65cc73a7201a7252750c76066a30 test.txtまた、
-t
オプションを付けることで、オブジェクトの種類を知ることができます。$ git cat-file -t d8329fc1cc938780ffdd9f94e0d364e0ea74f579 tree無事にツリーオブジェクトを作成することができました。
それでは続いて、もう1つツリーオブジェクトを作りましょう。
ここでは、現在ステージングされていない"versio 2"のファイルをステージングエリアに追加します。
$ git update-index test.txtさらにもう1つ新規ファイルを追加して、ステージング状態にします。
$ echo 'new file' > new.txt $ git update-index --add new.txt現在の状況は、以下となります。
$ git status # On branch master # # Initial commit # # Changes to be committed: # (use "git rm --cached <file>..." to unstage) # # new file: new.txt # new file: test.txt #この状態で、ツリーオブジェクトを作成します。
$ git write-tree 0155eb4229851634a0f03eb265b69f5a2d56f341これで、2つ目のツリーオブジェクトを作成する事ができました。中身を確認してみます。
$ git cat-file -p 0155eb4229851634a0f03eb265b69f5a2d56f341 100644 blob fa49b077972391ad58037050f2a75f74e3671e92 new.txt 100644 blob 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a test.txtこのツリーは2つのデータオブジェクトを保持しています。 そしてtest.txtは、ハッシュ値から分かる通り、"version 2"のデータです。
それではここで、最初のツリー(
d8329fc1cc938780ffdd9f94e0d364e0ea74f579
)を2つ目のツリーのサブディレクトリとして、ステージングエリアに追加してみましょう。
git read-tree
という内部コマンドを使うことで、ステージングエリア内にツリーを読み込む事ができます。
また、--prefix=(ディレクトリ名)
オプションを付けることで、ステージングエリアの中に、既存のツリーをサブディレクトリとして読み込むことができます。
そしてその後、git write-tree
でツリーを作成します。$ git read-tree --prefix=bak d8329fc1cc938780ffdd9f94e0d364e0ea74f579 $ git write-tree 3c4e9cd789d88d8d89c1073707c3585e41b0e614 $ git cat-file -p 3c4e9cd789d88d8d89c1073707c3585e41b0e614 040000 tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579 bak 100644 blob fa49b077972391ad58037050f2a75f74e3671e92 new.txt 100644 blob 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a test.txtさてここで作成したツリーは、2つのBlobデータと、1つのツリーオブジェクトを保持しています。 これらの構造を概念的に示すと、以下のようになります。
引用:http://git-scm.com/book/en/Git-Internals-Git-Objects
最後に
今回は、Gitの内部におけるデータ格納方法のうち、ツリーオブジェクトについて扱いました。 ツリーオブジェクトは、ステージングされた状態を保持するための大切な情報であり、次に説明するコミットオブジェクトで利用されます。 前回、今回、そして次に説明するコミットオブジェクトを学ぶことで、Gitのデータストアの基本を知ることができると思いますので、乞うご期待下さいw。最後までご覧頂きましてありがとうございました。