ミクシィには、探究心溢れるエンジニアがたくさん在籍しています。
その探究心は業務で扱う技術にとどまらず、趣味で書いているプログラムだったり、個人的に研究している言語だったりと、自身の気になった技術への追求も留まることを知りません。
そこで、社内のエンジニアに“好きな技術”について、思う存分に語ってもらうシリーズを始めました。
ルールはこの通り。
・業務で使っている技術でも、使われていない技術でもOK
・あくまでも個人的な見解で
・その技術のどこが面白いのか
・愛を込めて語り尽くしてもらう
第6回目は、エンジニアにとって馴染みのある「GitHub」を支える技術「Git」について、開発本部 インフラ室の藤田にアツく語ってもらいました。「Git」は一体どういった作りで、どこが面白いのか。その詳細をお届けします。
━━今回は、Gitについて話してくれると聞きました。
そうですね。「Git」は、ほぼエンジニア全員が使っていると言ってもいいツールですが、あまりその内実が知られていないのでは?と思って、テーマに選んでみました。
━━Gitはツールにあたるのでしょうか?
そもそもはLinuxの開発で使うためにリーナス・トーバルズによって2005年に開発された、ソースコードのバージョン管理ツールです。GitHubはそこに独自のインターフェースを付与して、より使いやすくしているサービスですね。
━━バージョン管理ということは、履歴を残しておくもの?
そうですね。履歴を残すこともそうですが、何か変更を加えてうまくいかなかった場合、何月何日のどのステータスまで巻き戻すかを選んで、そこまでバージョンをすばやく戻すことも出来るんです。
━━なるほど。でもなぜGitに興味を持ったのでしょうか?
出会いとしては、学生の頃に何の気なしにツールとして触っていたのですが…ミクシィに入社し、「Git研修」を受けた際に驚いたんです。自分が想像していた内部構造よりも、かなり複雑な構造になっていて、「なんでこんな作りになっているんだ?」と興味を持ち始めたのが大きなきっかけですね。
━━構造に興味を持ったと。
Gitの登場以前は、「集中型」というシステムがスタンダードだった背景があります。「集中型」の代表的なツールとしては、CVS、Subversionなどがあるのですが、これらは1つのリポジトリにあるファイルを同時に一人しか触れなかったんです。対してGitは、「分散型」という特徴がありまして…。100人で開発を行っていると、順番を待つ必要があった。
「集中型」のツールはサーバーに何か変更を加えた時、コミットがすぐに中央リポジトリに反映される仕組みなんです。でも、リポジトリが1つだと周囲への影響範囲も大きく、大規模な開発を並行して行うことがやりづらい…その使命を背負って出てきたのが「Git」なんですね。
「分散型」の特徴としては、それぞれのPC上にリポジトリを持っていて、立場としてはサーバーもPCも対等。手元にリポジトリがあるので、「集中型」と違ってネットワークを介さずに見られるのも特徴です。手元でコミットを整理できるし、バージョン管理も手元で出来る。そうすると、大規模な並行した開発がグッとやりやすくなるんです。
━━メリットは他にも?
リポジトリが手元にある、ということは実験的な開発もしやすいんです。自分が変更を加えた部分が勝手に反映されるわけではないので、一旦書いてみて、うまく整理できればpushする…といった実装が可能になるんですね。また、先に話した「GitHub」などのホスティングサービスを使えば、1からサーバーを立てずとも、複数人でバージョン管理をしながら開発が行えます。
ブロックチェーンと構造は同じ?
━━衝撃を受けたのは、そういった構造なんですか?
いえ、衝撃を受けたのは、なぜか「Git」は挙動が高速なんです。過去のファイルにアクセスするのも、コミットするのも速い。なぜこれが速いのか頭の中で想像していたのですが、その作りがすごくて…。
変更履歴を残す時、時系列にコミットAとコミットBがあった場合、そのAとBの差分だけを保存していると思ってたんです。そっちの方がシンプルだしな、とか思っていたのですが、実はすべてのコミットのスナップショットを取っているんですね。
これがどういうことか、というと差分だけじゃなく、コミットAとコミットBの全てを保存しているということなんです。表示されているのは差分だけなのですが、実は全てのスナップショットを取っていた。
これの何がすごいかというと、例えばあるコードを3年前のバージョンに戻すとなると、3年前のそのバージョンまでの全てのファイルをさかのぼって、全ての変更履歴を反映しないといけないので、すごく時間がかかるんです。バージョンを戻すだけで、反映に30分も時間がかかる、なんてことがザラだったんです。
━━ふむふむ。
でもGitは、変更があったファイル全ての履歴を残している、過去のスナップショットを取りに行くだけなので、さかのぼるまでの時間が少ないんです。
ただ、データの残し方が更にすごくて。単純にコミットAとコミットB…コミットXまでの全てのバージョン履歴のスナップショットを残している、と聞くとものすごくデータ容量が食うように思われるのですが、Gitはちゃんとそこに工夫を加えているんです。
コミットAとコミットBの重複した部分は、実際には重複したファイルとして存在しているわけではなく、ハッシュで区分されているんです。コミットAとBの差分を「a.txt」とすると…
こうしたテキストで表現されていて、新たな差分は「b.txt」として「a.txt」に相関したコミットハッシュを持っているので、ひとつの変更履歴だけを改ざんすることが出来ないんですね。例えば「b.txt」のハッシュは「a.txt」「c.txt」と相関したハッシュを持っているので、もし改ざんしようとすると、その全てのバージョンを改ざんしないといけなくなる。時系列含めてハッシュに含まれているので、変更ファイルだけを差し替えたり出来ない。
この構造は、いわゆるブロックチェーンと同じ構造なんです。1つのハッシュが前後のハッシュと相関した情報を持っていて、1つを改ざんしようとしても簡単には出来ない。これが、Gitのすごいところですね。さらにその仕組のおかげで高速性を実現しているので、作った人半端ないな…と思います(笑)。
━━なるほど!
更に、「.pack」という特徴もあります。ハッシュによってコンテンツを管理することで効率良くスナップショットを作成できると言っても、所詮スナップショットですので差分保存に比べるとファイルサイズは非常に大きくなります。ディスクサイズが大きくなった現代ではローカルでの開発中にファイルサイズが問題になるケースはほとんどありませんが、ネットワークを経由してファイルを運ぶにはどうしてもその輸送コストが無視できません。
そこで、Gitは変更履歴を「.pack」という独自形式で圧縮してからネットワークに流します。「.pack」はスナップショット管理していた変更履歴を差分管理に変換しています(他にもいくつかの工夫によってファイルサイズを削減しています)。でも従来のバージョン管理ツールと同様に差分管理にしてしまうと、高速に動作するというGit最大のメリットが失われてしまうじゃないですか。
━━確かに。
Gitが賢いのはここからで「過去からの差分で現在の状態を保存」するのではなく「現在からの差分で過去の状態を保存」します。これにより、参照されることの多い最新のコミットに関しては適用する差分の数が少なく済みますので高速に展開することができます。反対に古いコミットの場合は適用する差分の数が多くなるため展開に時間がかかりますが、古いコミットが参照されるというのは実際にはあまり多くないですよね。ファイルサイズの削減という大きいメリットに対してデメリットが少ないため、良い落とし所かなと思います。
━━構造はよくわかりました。でもこのGitを使わずに開発するとなると、どれほど大変ですか?
例えば、明日リリースする機能と、来月リリースする機能をまず平行して開発できません。順を追って開発を進めていかないといけないので、明日リリースする機能をまず作ってからでないと、来月リリースする機能に手すらつけられない。だから、現代の頻繁にアップデートされるソフトウェアを開発する環境においては、凄惨な地獄が想像されますね…。
━━ちなみに、まだ惜しい部分もあったりするのでしょうか?
Gitは先に話した通り、リポジトリを手元のPCで持つので「集中型」よりもディスク容量は食いますね。あと、バイナリファイルを扱うには不適格…といった部分もありますが、ここを語りだすと長くなるので、これはまたいずれということで(笑)。
━━このGitの使い方って、エンジニアリング以外にも活かせそうですね。
書籍を作る場合なんかは、便利かもしれませんね。実際に、「技術書典」はGitを使ってバージョン管理をしながら作っていたりします。各著者のバージョンがあって、それを最終的にひとつの本としてコミットするわけなので、そのまま転用できますよね。
━━確かに。最後に、今気になっている技術もあるのでしょうか?
最近はRDB(Relational Data Base)にすごく興味があります。MySQLなどの、現在一般的なDBなのですが、これほど使われているDBってどんな構造をしていて、どうすれば作れるのだろう…と、業務外の時間に学んでみたりしていますね。
━━ありがとうございます。次はRDBについても話を聞ける機会を楽しみにしてます!