こんにちは。東京技術チームの高崎です。
先日の社内勉強会でマネージャーの趙さんが「Git勉強会」を開催してくれましたので、その内容を共有したいと思います。
Gitの由来
Gitは元々のLinuxの開発者リーナス・トーバルズ(Linus Benedict Torvalds)が開始したオープンソースのバージョン管理ツールです
きっかけは、元々Linux開発でBitMover社が開発したBitKeeperというツールをバージョン管理ツールとして使用していました。しかし、同社とライセンス契約関するトラブルに発展し結果的にライセンスを剥奪され、それに変わる新しいバージョン管理プロジェクトの開発を開始しました。
2005年にリーナスはGitのコア機能開発にに着手し、2週間後に本体の機能開発を完了しました。 また2008年にGithubがリリースされ、Gitは(特にOSSに関する)システム開発におけるデファクトスタンダードへと進化していきます。
Gitの原理
Gitは様々な機能を有していますが、基本機能は次の4つ領域を使って実現しています。
作業ディレクトリ(working directory)
・実際にコードを修正する作業領域。ローカルのディレクトリを開いて見えるコードやファイルはこの作業ディレクトリです。git addコマンドでステージング領域へファイルを登録します。
ステージング領域(staging area/index)
・Gitには「ステージング領域」または「インデックス」と呼ばれるものがあります。これは、コミットを完了する前にコミットをフォーマットして確認できる中間領域です。git commitコマンドでローカルリポジトリへステージング領域にあるファイルを一括登録します。
ローカルリポジトリ(local repository)
・ローカルのGitリポジトリです。コミットごとの変更した差分が保存されます。git pushコマンドでリモートリポジトリへコミット内容を送信します。また、ローカルリポジトリをcheckoutすることで、ユーザはworking directoryを別のbranchに切り替えることが出来ます。
リモートリポジトリ(remote repository)
・ローカルリポジトリの変更点を保持します。一般的には、GitHub、GitLab、BitbucketといったGitのホスティングサービス上に構築され、複数の開発者がリモートリポジトリをコピー (clone, fetch)元として、ローカルリポジトリを構築します。
Gitのディレクトリ構造
Gitはどのようにしてバージョン情報を管理しているのでしょうか?その原理を探るために、.gitディレクトリのtree情報をみてみましょう。
すると様々なディレクトリやファイルが存在することがわかります。例えば、HEADファイルは、今自分が作業している場所を示すポインタを管理しているファイルです。HEADがブランチを指すことで自分が現在いるブランチがどれか確認できる仕組みになっています。
上記のように、作業ブランチを切り替えるとHEADファイルの内容も切り替わります。Gitはこのファイルを参照することで、現在の作業ブランチを判断していることが分かると思います。
またaddやcommitされたファイルの実体はobjectsというディレクトリに格納されます。
どのようにファイルが格納されるのでしょうか?まず、ファイルがcommitされた時、ステージされたファイル名にblobファイルサイズ\0を追加した文字列のハッシュ値を計算します (SHA1)。その値の最初の2ビットがディレクトリ名、最後の38ビットがファイル名となり、 objectsディレクトリに格納されます。
3つのオブジェクトタイプ
このように、ファイルの実体はobjectsディレクトリにコミット毎に保存されていきますが、実際には以下の3つの種類のobjectが格納されます。(今回の範囲ではないのでtag objectは割愛しま す。)
tree object(階層構造)
・Blobオブジェクトや別のTreeオブジェクトを管理する。ファイルシステムの「ディレクトリ」 に対応。blobはファイル名を管理していないので、blobオブジェクトとファイル名を対応させるのも、treeの役割。
blob object(ファイル本体)
・ファイルを圧縮したもの。ファイルシステムの「ファイル」に対応。
commit object(コミットログ)
・コミットのスナップショットに対応するTreeオブジェクトに、親コミット、コミットメッセージなどを付加する。
上記は1つのコミットを作成した場合に、作成されるObjectsの関連イメージです。このように、1つのコミットを操作した場合、Commitオブジェクトが作られ、そこに関連する作者名や、コミットメッセージが記録されます。その後、ディレクトリに相当するtreeオブジェクトがファイル名とファイルの実体(blobオブジェクト)の関連付けを行っていることがイメージ出来ると思います。
まとめ
このように普段何気なく使っているツールでも深堀りしてみると、知らないデータ構造や仕組みを知ることが出来て、大変勉強になりました!
特にGitはいまの開発になくてはならないツールなので、その歴史をしれたのも個人的に面白かったです。