見出し画像

gitが優れている4つの理由

さすがにgitを使ってない職場はそうそうないとは思うし、あったとしても僕がその職場(いまさらgitを使わない職場)は、僕とは相性ゲロ悪いのが分かっているので、そういう職場に行くことはないんですが、意外にgitの便利機能を知らない人が多いのでは?と思ったので、gitがSubversion(svn)と比較して優れている点を上げつつ、gitの便利機能を紹介します。

この記事を書いたきっかけは、僕自身が人生で「gitなんて使わなくてもsvnで十分だろ?」って言った人が数人、つまり両手の指で足りる人数くらいはいて、そういった人たちの思考がほぼ理解不能だったというのがあります。

たとえば、svnは知ってるけどgitを覚えるのが辛いって人は、ソフトウェアエンジニアリングとは極めて相性が悪い人なので、svn関係なく、別の職業に就くことを強く推奨します。

そのケースを除いたうえで、svnで十分だろ?って言ってる人は、二種類あると思ってて、svnのツラミを知らないひとか、gitではできるけどsvnでは出来ないことをできるって知らないひとか、その両方なんだと理解をしています。

そこで、svnでは出来ないこと、gitの優位な点について今回の記事を書きます。

mergeが賢い

これはgitとsvnの根幹の仕組みが違うため、絶対に覆せないポイントです。雑にいうとgitの方が、過去の変更点を考慮したmergeをするので、機械的に差分だけ見るよりは遥かに賢いmergeをしてくれます。

svnでは、ちょっとしたことで、クソしょうもないmergeが発生していましたが、そもそも不要であればmerge自体が発生しません。

これはそこかしこで度々言われてる利点なんで、必要以上の説明は省きましょう。

ブランチやタグを生成するコストがゼロ

ブランチやタグをゼロ秒で生成できます。

こういう超絶短時間低コストでできること、というのは実は開発手順に革命的な進化をもたらすことがあります。昨今流行っているツールの多くは実はこういった性質を持っています。Dockerなんかも似たような性質を持っているところがあります。(あっちはゼロコストとは言わないけど、低コスト化することで、できることを増やしたという意味では同じです)

ブランチを無限に作って消していいということは、ちょっとした実験をするときに簡単にブランチ・タグを作ったり消したりできるということです。push するブランチだけチームのルールに従っていればいいのです。

作業中(Work In Progress / WIP)の状態でも気軽に専用のブランチにコミットしてもいいですし、ちょっとした違いを見るために2つのブランチにそれぞれ違うコミットをしても構いません。

作業状態のスナップショットをゼロコストで無限に作成できると言えば、価値を理解していただけるでしょうか?

ちなみに、同様の目的に使えるコマンドが git stash です。git stash を実行すると、現時点のまだコミットされていない作業中状態を stash という仮の保存領域に入れて、前コミットの状態にリセットします。git stash pop を実行すると、作業状態を復元してくれます。

git stash pop も賢くて、別のブランチに切り替えようが、git fetch だの merge した状態でも、作業状態を復元してくれます。これは、git の merge が賢いからこそできる機能であり、git stash も git stash pop もゼロコストです。

ブランチを作成するコストが高い世界、つまりsvnの頃であれば、ブランチを作成することは遠慮の心理が働く世界でした。gitでは、少なくともローカルでは遠慮する必要性はゼロです。チームによってはチームのリポジトリではある程度ルールがあるかもしれませんが、これも基本的に遠慮するようなルールは不要です。

特定の動作を行わない限り情報を一切失うことが無い

この点も大切です。gitでは .git ディレクトリを物理削除する以外の方法では、基本的にリポジトリを爆破することはできません。可能なテロ行為は、git push origin :branch-name とかで、ブランチやタグを消して回るか、git push -f でブランチやタグのポインタを強制書き換えするくらいです。

・ .git ディレクトリを物理削除する
・ git push -f を行う
・ git push origin :branch-name などで、必要なブランチを削除する

ただし、これはある1つのリポジトリに対して行えるテロ行為にすぎません。gitの場合は分散リポジトリなので、誰かのリポジトリからの復元は簡単に可能です。もちろん、最悪なタイミングとかであれば容易ではないかもしれませんが。

また、.git ディレクトリの物理削除以外であれば、git職人芸で復活させることも可能です。これは git push -f や git push origin :branch-name などをしても、いじれるのが、ブランチやタグというポインタ情報だけに過ぎないからです。(このときの例外は git prune です)

言い換えましょう。git では git push や rm -rf .git を封じれば、ちょっとやそっと素人が何しても、git を破壊なんて出来ません。

容量に関してもたいていのケースではそんな莫大な容量を食うこともありません。プロダクトのすべての歴史を保存しておいても、ディスク容量で困ることはまずありません。

svnよりも気楽に使えるシステムがgitです。

また、gitの内部構造を熟知していれば、いざというときにあれこれできるシステムでもあります。何かあったときにコマンドを数個叩けば、だいたいなんとでもできるという安心感は、システムの堅牢性への信頼です。

・ すべての歴史が残ってる安心感
・ まず壊すことができないというシステムの堅牢性
・ 仕組みを熟知しているgit職人芸を使えばだいたいなんでもできる

大規模開発に耐えられる

gitはそもそも世界最大級のOSS開発である、Linux kernel の開発のために生み出されたプロダクトです。そのため、全世界の数百人・数千人・数万人が、百万コミット(この記事を書いてる現時点で、GitHubの torvalds/linux リポジトリは901,208 コミットです)しようが何しようがびくともしないように設計されています。

svnは、前職のとき10万コミットを超えたあたりから一気に性能が落ちました。たかだか10万コミット程度に耐えられないシステムが使い物になるわけがありません。

gitの場合、コミットなどが膨大になったとき、最初の git clone (初期取得、first fetch)が重くなることはありますが、初回だけですし、最悪 --depth=n を指定すればいいだけです。

gitのだめなところ

一応最後に、gitのだめなところについても書いておきます。

バイナリファイルの扱いは苦手なため、バイナリアセットを多用するゲーム業界なんかには向いていないかもしれません。まぁそういう用途では別のバージョン管理可能なアセットツールとかに逃げることになるかもしれません。

git CLI(コマンドラインインターフェース)はぶっちゃけクソです。人類にとって極めて分かりづらいインターフェースをしています。

たとえば、ブランチ削除は git branch -D branch-name で、ブランチ作成は git checkout -b branch-name です。リモートブランチの削除は git push origin :branch-name です。初見でこれらを使いこなせる人いたら褒めたいです。

git log だけだと、歴史が分かりづらいため、オプションを指定することがあります。たとえば、git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative とかです。ぶっちゃけ覚えたり打ち込んだりできないので、たいていの人は、.gitconfig でエイリアスを貼ったりしています。

じつはGUIツールを使わなくても、頑張ってオプションをいじりまくれば、そこそこの見栄えで状態を把握できたりもするのです。まぁ面倒なので、だいたいはぐぐって他の人の設定を探して導入したりする人が大半ですけど。(かくいう僕もそう)

そういうわけで、git CLI は、svn や cvn や rcs やその他よりも遥かに高機能過ぎるのもあって、あまりにも複雑怪奇かつ、非直感的です。これは、git の悪いところだとは思っています。

この記事を読んでもsvnでいいと思える人はいます?

いるのであれば、ぜひその理由を教えていただけると、後ほどの参考になるかもしれませんし、さらにこの記事を掘り下げることができるかもしれません。気が向いたらぜひ理由を教えていただけると幸いです。

あと、git のここが優れてるとか、この記事のここが間違っているというご指摘なんかもいただければ幸いです。

この記事が気に入ったらサポートをしてみませんか?