[git] Gitの内部におけるデータ格納方法について
こんにちは、@yoheiMuneです。
先日に引き続き、gitの内部の仕組みについてブログを書きたいと思います。
Gitの内部(はじめに)でも簡単に触れましたが、gitは連想記憶ファイルシステム(content-addressable filesystem)上に構築されたバージョン管理システムです。 これは、Gitのコア部分が、キーバリューから成るデータストアである、ということを意味しています。そしてそのデータは、
まずは、新規にGitレポジトリを作成し、
さて、
それでは、格納したデータが
さて、この記事では主にデータを対象に、
Pro Git | git-scm.com/book
最後までご覧頂きましてありがとうございます。
先日に引き続き、gitの内部の仕組みについてブログを書きたいと思います。
Special Thanks to http://flic.kr/p/eGGbYz
この記事で伝えたいこと
この記事の目的は、なぜGitが連想記憶ファイルシステム(content-addressable filesystem)なのかを理解してもらう、ということです。 前回から引き続き、Gitの内部の仕組みを扱います。Gitのオブジェクト
以下の内容は、Pro Gitを多く参照しています。
Gitの内部(はじめに)でも簡単に触れましたが、gitは連想記憶ファイルシステム(content-addressable filesystem)上に構築されたバージョン管理システムです。 これは、Gitのコア部分が、キーバリューから成るデータストアである、ということを意味しています。そしてそのデータは、
.git/objects/
で管理されます。.git/objects/
にデータが増えるタイミングは、通常、git commit
などのコマンドが実行された時で、コミット対象のファイルのデータが格納されます。
この記事ではgit commit
コマンドではなく、内部コマンドを利用することで、Gitデータストアの仕組みについて触れたいと思います。まずは、新規にGitレポジトリを作成し、
.git/objects/
の中を見てみましょう。
$ mkdir test $ cd test $ git init Initialized empty Git repository in /tmp/test/.git/ # 中身を全部確認してみる $ find .git/objects .git/objects .git/objects/info .git/objects/pack # ファイル(Notディレクトリ)の存在を確認する $ find .git/objects -type f $
info
とpack
というディレクトリが存在し、ファイルは存在していません。
つまりデータは何も格納されていない、空のレポジトリということです。Gitデータストアにデータを保存する
それでは、Gitの内部コマンドであるgit hash-object
を使って、Gitデータベースにデータを保存してみましょう。
$ echo 'test content' | git hash-object -w --stdin d670460b4b4aece5915caf5c68d12f560a9fe3e4
-w
オプションは、hash-object
コマンドに、オブジェクトを格納するように伝えます。-w
を付与しない場合には、受け取ったデータに対応するキーは何かを返すだけです。--stdin
は標準入力をデータとして受け取るためのオプションです。
これを指定しない場合には、hash-object
はファイルパスを探そうとします。さて、
hash-object
を実行した結果、40文字のハッシュ値を得られました。この値はSHA-1で生成した値で、Gitデータベースに保存したデータのキーです。このハッシュ値は、git log
などで見慣れたものではないでしょうか。それでは、格納したデータが
.git/objects/
に存在するか確認しましょう。$ find .git/objects -type f .git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4
.git/objects/
に保存されていることが分かります。見ると分かりますが、40文字のハッシュ値のうち、最初の2文字をディレクトリ名に割り当て、残りの38文字をファイル名に割り当てています。Gitデータストアからデータを取り出す
このファイルをcat
コマンドで表示してみましょう。$ cat .git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4 xK??OR04f(I-.QH??+I?+?K?ううう、文字化けした値が返ってきました。これは、格納されたデータは圧縮されているため、文字列として表示すると文字化けしてしまうのです。 具体的な中身を確認するためには、内部コマンドである
git cat-file
を利用します。$ git cat-file -p d670460b4b4aece5915caf5c68d12f560a9fe3e4 test content今度はちゃんと、保存したデータが表示されました。
-p
オプションを付けることで、コンテンツを分かりやすく表示する事ができます。簡単なバージョン管理を行ってみる
今までの内容を利用することで、簡単なバージョン管理を行う事ができます。 ここでは、test.txt
に複数回書き込んだ後に、最初の書き込みに戻す、ということをやってみましょう。# test.txtを新規に作成します $ echo 'version 1' > test.txt # Gitデータベースに書き込みます $ git hash-object -w test.txt 83baae61804e65cc73a7201a7252750c76066a30これで
test.txt
のバージョン1のデータがGit上に作成されました。
続いて、バージョン2を作成します。# 内容を上書きする $ echo 'version 2' > test.txt # Gitデータベースに書き込みます $ git hash-object -w test.txt 1f7a7a472abf3dd9643fd615f6da379c4acb3e3aこれで、バージョン2が作成できました。
.git/objects/
の格納状況を確認してみます。$ find .git/objects -type f .git/objects/1f/7a7a472abf3dd9643fd615f6da379c4acb3e3a # test.txtのバージョン2 .git/objects/83/baae61804e65cc73a7201a7252750c76066a30 # test.txtのバージョン1 .git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4 # 最初の説明で作ったものちゃんとデータが保存されていますね。 ここで、text.txtのバージョン1の内容に戻して(revertして)みましょう。
git cat-file
コマンドを利用します。$ git cat-file -p 83baae61804e65cc73a7201a7252750c76066a30 > test.txt $ cat test.txt version 1ちゃんと戻りましたね。バージョン2の内容にするには、以下のように行います。
$ git cat-file -p 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a > test.txt $ cat test.txt version 2Gitデータベースから任意の状態のtest.txtが復元できますね。
なぜGitが連想記憶ファイルシステムなのか
以上、簡単な説明ですが、Gitのデータ保存の仕組みについて説明しました。 説明で触れた通り、SHA-1で生成した40文字のハッシュ値を使うことで、任意のファイルの任意の状態にアクセスすることが出来ます。 つまり、40文字のハッシュ値がキーであり、保存されたデータがバリューであり、 それを保存するGitはキーバリューストア(Key-Value Store)なのです。さて、この記事では主にデータを対象に、
.git/objects/
に保存しましたが、他にもツリーオブジェクトやコミットオブジェクトというオブジェクトも存在します。今後の記事でそれらも扱えればと思います。参考資料
Gitの内部挙動を理解するために、以下の資料を参照しました。ありがとうございます。Pro Git | git-scm.com/book
最後に
今回は、Gitの内部の仕組みについて、Objectを取り上げて説明しました。Gitがなぜ連想記憶ファイルシステムなのか、少しでも理解頂けていたら幸いです。 Gitの内部構造、学び始めると楽しいですね。最後までご覧頂きましてありがとうございます。